<commit_before>/* This file is part of Zanshin

   Copyright 2014 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) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   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 "akonaditagqueries.h"

#include "akonadicollectionfetchjobinterface.h"
#include "akonadiitemfetchjobinterface.h"
#include "akonaditagfetchjobinterface.h"

#include "akonadimonitorimpl.h"
#include "akonadiserializer.h"
#include "akonadistorage.h"

#include "utils/jobhandler.h"

using namespace Akonadi;

TagQueries::TagQueries(QObject *parent)
    : QObject(parent),
      m_storage(new Storage),
      m_serializer(new Serializer),
      m_monitor(new MonitorImpl),
      m_fetchContentTypeFilter(StorageInterface::Tasks|StorageInterface::Notes),
      m_ownInterfaces(true)
{
    connect(m_monitor, SIGNAL(tagAdded(Akonadi::Tag)), this, SLOT(onTagAdded(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagRemoved(Akonadi::Tag)), this, SLOT(onTagRemoved(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagChanged(Akonadi::Tag)), this, SLOT(onTagChanged(Akonadi::Tag)));

    connect(m_monitor, SIGNAL(itemAdded(Akonadi::Item)), this, SLOT(onItemAdded(Akonadi::Item)));
    connect(m_monitor, SIGNAL(itemRemoved(Akonadi::Item)), this, SLOT(onItemRemoved(Akonadi::Item)));
    connect(m_monitor, SIGNAL(itemChanged(Akonadi::Item)), this, SLOT(onItemChanged(Akonadi::Item)));
}

TagQueries::TagQueries(StorageInterface *storage, SerializerInterface *serializer, MonitorInterface *monitor)
    : m_storage(storage),
      m_serializer(serializer),
      m_monitor(monitor),
      m_fetchContentTypeFilter(StorageInterface::Tasks|StorageInterface::Notes),
      m_ownInterfaces(false)
{
    connect(m_monitor, SIGNAL(tagAdded(Akonadi::Tag)), this, SLOT(onTagAdded(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagRemoved(Akonadi::Tag)), this, SLOT(onTagRemoved(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagChanged(Akonadi::Tag)), this, SLOT(onTagChanged(Akonadi::Tag)));

    connect(monitor, SIGNAL(itemAdded(Akonadi::Item)), this, SLOT(onItemAdded(Akonadi::Item)));
    connect(monitor, SIGNAL(itemRemoved(Akonadi::Item)), this, SLOT(onItemRemoved(Akonadi::Item)));
    connect(monitor, SIGNAL(itemChanged(Akonadi::Item)), this, SLOT(onItemChanged(Akonadi::Item)));
}

TagQueries::~TagQueries()
{
    if (m_ownInterfaces) {
        delete m_storage;
        delete m_serializer;
        delete m_monitor;
    }
}

void TagQueries::setApplicationMode(TagQueries::ApplicationMode mode)
{
    if (mode == TasksOnly) {
        m_fetchContentTypeFilter = StorageInterface::Tasks;
    } else if (mode == NotesOnly) {
        m_fetchContentTypeFilter = StorageInterface::Notes;
    }
}

TagQueries::TagResult::Ptr TagQueries::findAll() const
{
    if (!m_findAll) {
        {
            TagQueries *self = const_cast<TagQueries*>(this);
            self->m_findAll = self->createTagQuery();
        }

        m_findAll->setFetchFunction([this] (const TagQuery::AddFunction &add) {
            TagFetchJobInterface *job = m_storage->fetchTags();
            Utils::JobHandler::install(job->kjob(), [this, job, add] {
                for (Akonadi::Tag tag : job->tags())
                    add(tag);
            });
        });

        m_findAll->setConvertFunction([this] (const Akonadi::Tag &tag) {
            return m_serializer->createTagFromAkonadiTag(tag);
        });

        m_findAll->setUpdateFunction([this] (const Akonadi::Tag &akonadiTag, Domain::Tag::Ptr &tag) {
            m_serializer->updateTagFromAkonadiTag(tag, akonadiTag);
        });
        m_findAll->setPredicateFunction([this] (const Akonadi::Tag &akonadiTag) {
            return akonadiTag.type() == Akonadi::Tag::PLAIN;
        });
        m_findAll->setRepresentsFunction([this] (const Akonadi::Tag &akonadiTag, const Domain::Tag::Ptr &tag) {
            return m_serializer->representsAkonadiTag(tag, akonadiTag);
        });
    }

    return m_findAll->result();
}

TagQueries::ArtifactResult::Ptr TagQueries::findTopLevelArtifacts(Domain::Tag::Ptr tag) const
{
    Akonadi::Tag akonadiTag = m_serializer->createAkonadiTagFromTag(tag);
    if (!m_findTopLevel.contains(akonadiTag.id())) {
        ArtifactQuery::Ptr query;
        {
            TagQueries *self = const_cast<TagQueries*>(this);
            query = self->createArtifactQuery();
            self->m_findTopLevel.insert(akonadiTag.id(), query);
        }

        query->setFetchFunction([this, akonadiTag] (const ArtifactQuery::AddFunction &add) {
            CollectionFetchJobInterface *job = m_storage->fetchCollections(Akonadi::Collection::root(),
                                                                           StorageInterface::Recursive,
                                                                           m_fetchContentTypeFilter);
            Utils::JobHandler::install(job->kjob(), [this, job, add] {
                if (job->kjob()->error() != KJob::NoError)
                    return;

                for (auto collection : job->collections()) {
                    ItemFetchJobInterface *job = m_storage->fetchItems(collection);
                    Utils::JobHandler::install(job->kjob(), [this, job, add] {
                        if (job->kjob()->error() != KJob::NoError)
                            return;

                        for (auto item : job->items())
                            add(item);
                    });
                }
            });
        });
        query->setConvertFunction([this] (const Akonadi::Item &item) {
            if (m_serializer->isTaskItem(item)) {
                auto task = m_serializer->createTaskFromItem(item);
                return Domain::Artifact::Ptr(task);

            } else if (m_serializer->isNoteItem(item)) {
                auto note = m_serializer->createNoteFromItem(item);
                return Domain::Artifact::Ptr(note);

            }
            //The conversion must never fail, otherwise we create an endless loop (child of invalid node is invalid).
            //We therefore catch this case in the predicate.
            Q_ASSERT(false);
            return Domain::Artifact::Ptr();
        });
        query->setUpdateFunction([this] (const Akonadi::Item &item, Domain::Artifact::Ptr &artifact) {
            if (auto task = artifact.dynamicCast<Domain::Task>()) {
                m_serializer->updateTaskFromItem(task, item);
            } else if (auto note = artifact.dynamicCast<Domain::Note>()) {
                m_serializer->updateNoteFromItem(note, item);
            }
        });
        query->setPredicateFunction([this, tag] (const Akonadi::Item &item) {
            if (m_serializer->isTaskItem(item)) {
                return false;
            }
            if (!m_serializer->isNoteItem(item)) {
                return false;
            }
            return m_serializer->isTagChild(tag, item);
        });
        query->setRepresentsFunction([this] (const Akonadi::Item &item, const Domain::Artifact::Ptr &artifact) {
            return m_serializer->representsItem(artifact, item);
        });
    }

    return m_findTopLevel.value(akonadiTag.id())->result();
}

void TagQueries::onTagAdded(const Tag &tag)
{
    foreach (const TagQuery::Ptr &query, m_tagQueries)
        query->onAdded(tag);
}

void TagQueries::onTagRemoved(const Tag &tag)
{
    foreach (const TagQuery::Ptr &query, m_tagQueries)
        query->onRemoved(tag);
}

void TagQueries::onTagChanged(const Tag &tag)
{
    foreach (const TagQuery::Ptr &query, m_tagQueries)
        query->onChanged(tag);
}

void TagQueries::onItemAdded(const Item &item)
{
    foreach (const ArtifactQuery::Ptr &query, m_artifactQueries)
        query->onAdded(item);
}

void TagQueries::onItemRemoved(const Item &item)
{
    Q_UNUSED(item);
}

void TagQueries::onItemChanged(const Item &item)
{
    foreach (const ArtifactQuery::Ptr &query, m_artifactQueries)
        query->onChanged(item);
}

TagQueries::TagQuery::Ptr TagQueries::createTagQuery()
{
    auto query = TagQueries::TagQuery::Ptr::create();
    m_tagQueries << query;
    return query;
}

TagQueries::ArtifactQuery::Ptr TagQueries::createArtifactQuery()
{
    auto query = TagQueries::ArtifactQuery::Ptr::create();
    m_artifactQueries << query;
    return query;
}
<commit_msg>TagQueries: react to item removals<commit_after>/* This file is part of Zanshin

   Copyright 2014 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) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   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 "akonaditagqueries.h"

#include "akonadicollectionfetchjobinterface.h"
#include "akonadiitemfetchjobinterface.h"
#include "akonaditagfetchjobinterface.h"

#include "akonadimonitorimpl.h"
#include "akonadiserializer.h"
#include "akonadistorage.h"

#include "utils/jobhandler.h"

using namespace Akonadi;

TagQueries::TagQueries(QObject *parent)
    : QObject(parent),
      m_storage(new Storage),
      m_serializer(new Serializer),
      m_monitor(new MonitorImpl),
      m_fetchContentTypeFilter(StorageInterface::Tasks|StorageInterface::Notes),
      m_ownInterfaces(true)
{
    connect(m_monitor, SIGNAL(tagAdded(Akonadi::Tag)), this, SLOT(onTagAdded(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagRemoved(Akonadi::Tag)), this, SLOT(onTagRemoved(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagChanged(Akonadi::Tag)), this, SLOT(onTagChanged(Akonadi::Tag)));

    connect(m_monitor, SIGNAL(itemAdded(Akonadi::Item)), this, SLOT(onItemAdded(Akonadi::Item)));
    connect(m_monitor, SIGNAL(itemRemoved(Akonadi::Item)), this, SLOT(onItemRemoved(Akonadi::Item)));
    connect(m_monitor, SIGNAL(itemChanged(Akonadi::Item)), this, SLOT(onItemChanged(Akonadi::Item)));
}

TagQueries::TagQueries(StorageInterface *storage, SerializerInterface *serializer, MonitorInterface *monitor)
    : m_storage(storage),
      m_serializer(serializer),
      m_monitor(monitor),
      m_fetchContentTypeFilter(StorageInterface::Tasks|StorageInterface::Notes),
      m_ownInterfaces(false)
{
    connect(m_monitor, SIGNAL(tagAdded(Akonadi::Tag)), this, SLOT(onTagAdded(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagRemoved(Akonadi::Tag)), this, SLOT(onTagRemoved(Akonadi::Tag)));
    connect(m_monitor, SIGNAL(tagChanged(Akonadi::Tag)), this, SLOT(onTagChanged(Akonadi::Tag)));

    connect(monitor, SIGNAL(itemAdded(Akonadi::Item)), this, SLOT(onItemAdded(Akonadi::Item)));
    connect(monitor, SIGNAL(itemRemoved(Akonadi::Item)), this, SLOT(onItemRemoved(Akonadi::Item)));
    connect(monitor, SIGNAL(itemChanged(Akonadi::Item)), this, SLOT(onItemChanged(Akonadi::Item)));
}

TagQueries::~TagQueries()
{
    if (m_ownInterfaces) {
        delete m_storage;
        delete m_serializer;
        delete m_monitor;
    }
}

void TagQueries::setApplicationMode(TagQueries::ApplicationMode mode)
{
    if (mode == TasksOnly) {
        m_fetchContentTypeFilter = StorageInterface::Tasks;
    } else if (mode == NotesOnly) {
        m_fetchContentTypeFilter = StorageInterface::Notes;
    }
}

TagQueries::TagResult::Ptr TagQueries::findAll() const
{
    if (!m_findAll) {
        {
            TagQueries *self = const_cast<TagQueries*>(this);
            self->m_findAll = self->createTagQuery();
        }

        m_findAll->setFetchFunction([this] (const TagQuery::AddFunction &add) {
            TagFetchJobInterface *job = m_storage->fetchTags();
            Utils::JobHandler::install(job->kjob(), [this, job, add] {
                for (Akonadi::Tag tag : job->tags())
                    add(tag);
            });
        });

        m_findAll->setConvertFunction([this] (const Akonadi::Tag &tag) {
            return m_serializer->createTagFromAkonadiTag(tag);
        });

        m_findAll->setUpdateFunction([this] (const Akonadi::Tag &akonadiTag, Domain::Tag::Ptr &tag) {
            m_serializer->updateTagFromAkonadiTag(tag, akonadiTag);
        });
        m_findAll->setPredicateFunction([this] (const Akonadi::Tag &akonadiTag) {
            return akonadiTag.type() == Akonadi::Tag::PLAIN;
        });
        m_findAll->setRepresentsFunction([this] (const Akonadi::Tag &akonadiTag, const Domain::Tag::Ptr &tag) {
            return m_serializer->representsAkonadiTag(tag, akonadiTag);
        });
    }

    return m_findAll->result();
}

TagQueries::ArtifactResult::Ptr TagQueries::findTopLevelArtifacts(Domain::Tag::Ptr tag) const
{
    Akonadi::Tag akonadiTag = m_serializer->createAkonadiTagFromTag(tag);
    if (!m_findTopLevel.contains(akonadiTag.id())) {
        ArtifactQuery::Ptr query;
        {
            TagQueries *self = const_cast<TagQueries*>(this);
            query = self->createArtifactQuery();
            self->m_findTopLevel.insert(akonadiTag.id(), query);
        }

        query->setFetchFunction([this, akonadiTag] (const ArtifactQuery::AddFunction &add) {
            CollectionFetchJobInterface *job = m_storage->fetchCollections(Akonadi::Collection::root(),
                                                                           StorageInterface::Recursive,
                                                                           m_fetchContentTypeFilter);
            Utils::JobHandler::install(job->kjob(), [this, job, add] {
                if (job->kjob()->error() != KJob::NoError)
                    return;

                for (auto collection : job->collections()) {
                    ItemFetchJobInterface *job = m_storage->fetchItems(collection);
                    Utils::JobHandler::install(job->kjob(), [this, job, add] {
                        if (job->kjob()->error() != KJob::NoError)
                            return;

                        for (auto item : job->items())
                            add(item);
                    });
                }
            });
        });
        query->setConvertFunction([this] (const Akonadi::Item &item) {
            if (m_serializer->isTaskItem(item)) {
                auto task = m_serializer->createTaskFromItem(item);
                return Domain::Artifact::Ptr(task);

            } else if (m_serializer->isNoteItem(item)) {
                auto note = m_serializer->createNoteFromItem(item);
                return Domain::Artifact::Ptr(note);

            }
            //The conversion must never fail, otherwise we create an endless loop (child of invalid node is invalid).
            //We therefore catch this case in the predicate.
            Q_ASSERT(false);
            return Domain::Artifact::Ptr();
        });
        query->setUpdateFunction([this] (const Akonadi::Item &item, Domain::Artifact::Ptr &artifact) {
            if (auto task = artifact.dynamicCast<Domain::Task>()) {
                m_serializer->updateTaskFromItem(task, item);
            } else if (auto note = artifact.dynamicCast<Domain::Note>()) {
                m_serializer->updateNoteFromItem(note, item);
            }
        });
        query->setPredicateFunction([this, tag] (const Akonadi::Item &item) {
            if (m_serializer->isTaskItem(item)) {
                return false;
            }
            if (!m_serializer->isNoteItem(item)) {
                return false;
            }
            return m_serializer->isTagChild(tag, item);
        });
        query->setRepresentsFunction([this] (const Akonadi::Item &item, const Domain::Artifact::Ptr &artifact) {
            return m_serializer->representsItem(artifact, item);
        });
    }

    return m_findTopLevel.value(akonadiTag.id())->result();
}

void TagQueries::onTagAdded(const Tag &tag)
{
    foreach (const TagQuery::Ptr &query, m_tagQueries)
        query->onAdded(tag);
}

void TagQueries::onTagRemoved(const Tag &tag)
{
    foreach (const TagQuery::Ptr &query, m_tagQueries)
        query->onRemoved(tag);
}

void TagQueries::onTagChanged(const Tag &tag)
{
    foreach (const TagQuery::Ptr &query, m_tagQueries)
        query->onChanged(tag);
}

void TagQueries::onItemAdded(const Item &item)
{
    foreach (const ArtifactQuery::Ptr &query, m_artifactQueries)
        query->onAdded(item);
}

void TagQueries::onItemRemoved(const Item &item)
{
    foreach (const ArtifactQuery::Ptr &query, m_artifactQueries)
        query->onRemoved(item);
}

void TagQueries::onItemChanged(const Item &item)
{
    foreach (const ArtifactQuery::Ptr &query, m_artifactQueries)
        query->onChanged(item);
}

TagQueries::TagQuery::Ptr TagQueries::createTagQuery()
{
    auto query = TagQueries::TagQuery::Ptr::create();
    m_tagQueries << query;
    return query;
}

TagQueries::ArtifactQuery::Ptr TagQueries::createArtifactQuery()
{
    auto query = TagQueries::ArtifactQuery::Ptr::create();
    m_artifactQueries << query;
    return query;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestGroupLeafVertices.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "vtkActor.h"
#include "vtkActor2D.h"
//#include "vtkDynamic2DLabelMapper.h"
#include "vtkGlyph3D.h"
#include "vtkGraphLayout.h"
#include "vtkGraphToPolyData.h"
#include "vtkGroupLeafVertices.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkSphereSource.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTableToTreeFilter.h"
#include "vtkTree.h"
#include "vtkTreeLayoutStrategy.h"
#include "vtkTreeMapViewer.h"

#define VTK_CREATE(type,name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

int TestGroupLeafVertices(int argc, char* argv[])
{
  int imode = 0; // Interactive mode
  for(int i = 1; i < argc; i++)
    {
    if (!strcmp(argv[i], "-I"))
      {
      imode = 1;
      continue;
      }

    cerr << argv[0] << " Options:\n  "
      << " -h (prints this message)\n  "
      << " -I (run interactively)\n  ";
    return 0;
    }

  VTK_CREATE(vtkTable, table);
  VTK_CREATE(vtkStringArray, nameArray);
  nameArray->SetName("name");
  VTK_CREATE(vtkStringArray, typeArray);
  typeArray->SetName("type");
  VTK_CREATE(vtkStringArray, colorArray);
  colorArray->SetName("color");

  nameArray->InsertNextValue("bobo");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("rex");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("brown");

  nameArray->InsertNextValue("bill");
  typeArray->InsertNextValue("cat");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("eli");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("spot");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("white");

  nameArray->InsertNextValue("roger");
  typeArray->InsertNextValue("cat");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("tweety");
  typeArray->InsertNextValue("bird");
  colorArray->InsertNextValue("white");

  nameArray->InsertNextValue("mike");
  typeArray->InsertNextValue("bird");
  colorArray->InsertNextValue("brown");

  nameArray->InsertNextValue("spike");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("brown");

  table->AddColumn(nameArray);
  table->AddColumn(typeArray);
  table->AddColumn(colorArray);

  //
  // Create a tree from the table
  //

  VTK_CREATE(vtkTableToTreeFilter, tableToTree);
  tableToTree->SetInput(table);
  tableToTree->Update();
  vtkTree* tree = tableToTree->GetOutput();
  for (vtkIdType i = 0; i < tree->GetNumberOfVertices(); i++)
    {
    cerr << i << " has parent " << tree->GetParent(i) << endl;
    }

  VTK_CREATE(vtkGroupLeafVertices, group);
  group->SetInputConnection(tableToTree->GetOutputPort());
  group->SetInputArrayToProcess(0, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "type");
  group->SetInputArrayToProcess(1, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "name");
  group->Update();
  tree = group->GetOutput();
  for (vtkIdType i = 0; i < tree->GetNumberOfVertices(); i++)
    {
    cerr << i << " has parent " << tree->GetParent(i) << endl;
    }

  VTK_CREATE(vtkGroupLeafVertices, group2);
  group2->SetInputConnection(group->GetOutputPort());
  group2->SetInputArrayToProcess(0, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "color");
  group2->SetInputArrayToProcess(1, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "name");
  group2->Update();
  tree = group2->GetOutput();
  for (vtkIdType i = 0; i < tree->GetNumberOfVertices(); i++)
    {
    cerr << i << " has parent " << tree->GetParent(i) << endl;
    }

  //
  // Render the tree
  //

  VTK_CREATE(vtkTreeLayoutStrategy, strategy);
  strategy->SetRadial(true);
  strategy->SetAngle(360);

  VTK_CREATE(vtkGraphLayout, layout);
  layout->SetInputConnection(group2->GetOutputPort());
  layout->SetLayoutStrategy(strategy);

  VTK_CREATE(vtkGraphToPolyData, graphToPoly);
  graphToPoly->SetInputConnection(layout->GetOutputPort());

  VTK_CREATE(vtkPolyDataMapper, polyMapper);
  polyMapper->SetInputConnection(graphToPoly->GetOutputPort());

  VTK_CREATE(vtkActor, polyActor);
  polyActor->SetMapper(polyMapper);
  polyActor->GetProperty()->SetColor(0.3, 0.3, 1.0);

  //
  // Make some labels
  //

#if 0
  VTK_CREATE(vtkDynamic2DLabelMapper, labelMapper);
  labelMapper->SetInputConnection(graphToPoly->GetOutputPort());
  labelMapper->SetLabelFormat("%s");
  labelMapper->SetLabelModeToLabelFieldData();
  labelMapper->SetFieldDataName("name");

  VTK_CREATE(vtkActor2D, labelActor);
  labelActor->SetMapper(labelMapper);
#endif

  //
  // Make some glyphs
  //

  VTK_CREATE(vtkSphereSource, sphere);
  sphere->SetRadius(0.05);
  sphere->SetPhiResolution(6);
  sphere->SetThetaResolution(6);

  VTK_CREATE(vtkGlyph3D, glyph);
  glyph->SetInputConnection(0, graphToPoly->GetOutputPort());
  glyph->SetInputConnection(1, sphere->GetOutputPort());

  VTK_CREATE(vtkPolyDataMapper, glyphMap);
  glyphMap->SetInputConnection(glyph->GetOutputPort());

  VTK_CREATE(vtkActor, glyphActor);
  glyphActor->SetMapper(glyphMap);
  glyphActor->GetProperty()->SetColor(0.3, 0.3, 1.0);

  //
  // Set up the main window
  //

  VTK_CREATE(vtkRenderer, ren);
  ren->AddActor(polyActor);
  //ren->AddActor(labelActor);
  ren->AddActor(glyphActor);

  VTK_CREATE(vtkRenderWindow, win);
  win->AddRenderer(ren);

  VTK_CREATE(vtkRenderWindowInteractor, iren);
  iren->SetRenderWindow(win);

  if (imode)
    {
    iren->Initialize();
    iren->Start();
    }

  return 0;
}
<commit_msg>COMP: fixed compiler error when VTK_USE_VIEWS is off<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestGroupLeafVertices.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "vtkActor.h"
#include "vtkActor2D.h"
//#include "vtkDynamic2DLabelMapper.h"
#include "vtkGlyph3D.h"
#include "vtkGraphLayout.h"
#include "vtkGraphToPolyData.h"
#include "vtkGroupLeafVertices.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkSphereSource.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTableToTreeFilter.h"
#include "vtkTree.h"
#include "vtkTreeLayoutStrategy.h"

#define VTK_CREATE(type,name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

int TestGroupLeafVertices(int argc, char* argv[])
{
  int imode = 0; // Interactive mode
  for(int i = 1; i < argc; i++)
    {
    if (!strcmp(argv[i], "-I"))
      {
      imode = 1;
      continue;
      }

    cerr << argv[0] << " Options:\n  "
      << " -h (prints this message)\n  "
      << " -I (run interactively)\n  ";
    return 0;
    }

  VTK_CREATE(vtkTable, table);
  VTK_CREATE(vtkStringArray, nameArray);
  nameArray->SetName("name");
  VTK_CREATE(vtkStringArray, typeArray);
  typeArray->SetName("type");
  VTK_CREATE(vtkStringArray, colorArray);
  colorArray->SetName("color");

  nameArray->InsertNextValue("bobo");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("rex");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("brown");

  nameArray->InsertNextValue("bill");
  typeArray->InsertNextValue("cat");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("eli");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("spot");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("white");

  nameArray->InsertNextValue("roger");
  typeArray->InsertNextValue("cat");
  colorArray->InsertNextValue("black");

  nameArray->InsertNextValue("tweety");
  typeArray->InsertNextValue("bird");
  colorArray->InsertNextValue("white");

  nameArray->InsertNextValue("mike");
  typeArray->InsertNextValue("bird");
  colorArray->InsertNextValue("brown");

  nameArray->InsertNextValue("spike");
  typeArray->InsertNextValue("dog");
  colorArray->InsertNextValue("brown");

  table->AddColumn(nameArray);
  table->AddColumn(typeArray);
  table->AddColumn(colorArray);

  //
  // Create a tree from the table
  //

  VTK_CREATE(vtkTableToTreeFilter, tableToTree);
  tableToTree->SetInput(table);
  tableToTree->Update();
  vtkTree* tree = tableToTree->GetOutput();
  for (vtkIdType i = 0; i < tree->GetNumberOfVertices(); i++)
    {
    cerr << i << " has parent " << tree->GetParent(i) << endl;
    }

  VTK_CREATE(vtkGroupLeafVertices, group);
  group->SetInputConnection(tableToTree->GetOutputPort());
  group->SetInputArrayToProcess(0, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "type");
  group->SetInputArrayToProcess(1, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "name");
  group->Update();
  tree = group->GetOutput();
  for (vtkIdType i = 0; i < tree->GetNumberOfVertices(); i++)
    {
    cerr << i << " has parent " << tree->GetParent(i) << endl;
    }

  VTK_CREATE(vtkGroupLeafVertices, group2);
  group2->SetInputConnection(group->GetOutputPort());
  group2->SetInputArrayToProcess(0, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "color");
  group2->SetInputArrayToProcess(1, 0, 0, vtkDataSet::FIELD_ASSOCIATION_VERTICES, "name");
  group2->Update();
  tree = group2->GetOutput();
  for (vtkIdType i = 0; i < tree->GetNumberOfVertices(); i++)
    {
    cerr << i << " has parent " << tree->GetParent(i) << endl;
    }

  //
  // Render the tree
  //

  VTK_CREATE(vtkTreeLayoutStrategy, strategy);
  strategy->SetRadial(true);
  strategy->SetAngle(360);

  VTK_CREATE(vtkGraphLayout, layout);
  layout->SetInputConnection(group2->GetOutputPort());
  layout->SetLayoutStrategy(strategy);

  VTK_CREATE(vtkGraphToPolyData, graphToPoly);
  graphToPoly->SetInputConnection(layout->GetOutputPort());

  VTK_CREATE(vtkPolyDataMapper, polyMapper);
  polyMapper->SetInputConnection(graphToPoly->GetOutputPort());

  VTK_CREATE(vtkActor, polyActor);
  polyActor->SetMapper(polyMapper);
  polyActor->GetProperty()->SetColor(0.3, 0.3, 1.0);

  //
  // Make some labels
  //

#if 0
  VTK_CREATE(vtkDynamic2DLabelMapper, labelMapper);
  labelMapper->SetInputConnection(graphToPoly->GetOutputPort());
  labelMapper->SetLabelFormat("%s");
  labelMapper->SetLabelModeToLabelFieldData();
  labelMapper->SetFieldDataName("name");

  VTK_CREATE(vtkActor2D, labelActor);
  labelActor->SetMapper(labelMapper);
#endif

  //
  // Make some glyphs
  //

  VTK_CREATE(vtkSphereSource, sphere);
  sphere->SetRadius(0.05);
  sphere->SetPhiResolution(6);
  sphere->SetThetaResolution(6);

  VTK_CREATE(vtkGlyph3D, glyph);
  glyph->SetInputConnection(0, graphToPoly->GetOutputPort());
  glyph->SetInputConnection(1, sphere->GetOutputPort());

  VTK_CREATE(vtkPolyDataMapper, glyphMap);
  glyphMap->SetInputConnection(glyph->GetOutputPort());

  VTK_CREATE(vtkActor, glyphActor);
  glyphActor->SetMapper(glyphMap);
  glyphActor->GetProperty()->SetColor(0.3, 0.3, 1.0);

  //
  // Set up the main window
  //

  VTK_CREATE(vtkRenderer, ren);
  ren->AddActor(polyActor);
  //ren->AddActor(labelActor);
  ren->AddActor(glyphActor);

  VTK_CREATE(vtkRenderWindow, win);
  win->AddRenderer(ren);

  VTK_CREATE(vtkRenderWindowInteractor, iren);
  iren->SetRenderWindow(win);

  if (imode)
    {
    iren->Initialize();
    iren->Start();
    }

  return 0;
}
<|endoftext|>


<commit_before>#include "mpdas.h"

CCache* Cache = 0;

void
CCache::SaveCache()
{
	std::string path = getenv("HOME");
	path.append("/.mpdascache");
	remove(path.c_str());
	std::ofstream ofs(path.c_str());
	if(!_entries.size()) {
		remove(path.c_str());
		return;
	}

	for(unsigned int i = 0; i < _entries.size(); i++) {
		centry_t* entry = _entries[i];
		if(entry->album)
			ofs << true << "\n";
		ofs << entry->artist << "\n";
		ofs << entry->title << "\n";
		ofs << entry->time << "\n";
		ofs << entry->starttime;
		if(entry->album)
			ofs << "\n" << entry->album;
		if(i+1 == _entries.size())
			ofs.flush();
		else
			ofs << std::endl;
	}
	ofs.close();
}

void
CCache::LoadCache()
{
	int length;
	std::string path = getenv("HOME");
	path.append("/.mpdascache");
	std::ifstream ifs(path.c_str(), std::ios::in|std::ios::binary);

	ifs.seekg (0, std::ios::end);
	length = ifs.tellg();
	ifs.seekg (0, std::ios::beg);

	while(ifs.good()) {
		if(length == ifs.tellg())
			break;
		std::string artist, album, title;
		bool gotalbum = false;
		int time;
		time_t starttime;

		ifs >> gotalbum;
		ifs.ignore(1);
		ifs >> artist;
		ifs >> title;
		ifs >> time;
		ifs.ignore(1);
		ifs >> starttime;
		ifs.ignore(1);
		if(gotalbum)
			getline(ifs, album);
		AddToCache(time, artist, title, album, starttime, true);
	}

	ifs.close();
	remove(path.c_str());
}

void
CCache::WorkCache()
{
	if(_failtime && time(NULL) - _failtime < 300) {
		return;
	}
	_failtime = 0;
	while(_entries.size()) {
		if(AudioScrobbler->Scrobble(_entries.front())) {
			curl_free((void*)_entries.front()->artist);
			curl_free((void*)_entries.front()->title);
			if(_entries.front()->album)
				curl_free((void*)_entries.front()->album);
			delete _entries.front();
			_entries.erase(_entries.begin());
		}
		else {
			eprintf("%s", "Error scrobbling. Trying again in 5 minutes.");
			_failtime = time(NULL);
			break;
		}
		sleep(1);
	}
	SaveCache();
}

void
CCache::AddToCache(int time, std::string artist, std::string title, std::string album, time_t starttime, bool escaped = false)
{
	centry_t* entry = new centry_t;
	bzero(entry, sizeof(centry_t));

	entry->time = time;
	if(!escaped) {
		entry->artist = (char*)curl_escape(artist.c_str(), 0);
		entry->title = (char*)curl_escape(title.c_str(), 0);
		if(album.size())
			entry->album = (char*)curl_escape(album.c_str(), 0);
	} else {
		entry->artist = new char[artist.size()+1];
		strcpy(entry->artist, artist.c_str());
		entry->title = new char[title.size()+1];
		strcpy(entry->title, title.c_str());
		if(album.size()) {
			entry->album = new char[album.size()+1];
			strcpy(entry->album, album.c_str());
		}
	}
	entry->starttime = starttime;
	_entries.push_back(entry);
	SaveCache();
}
<commit_msg>Re-implement re-handshaking after 3 scrobble errors<commit_after>#include "mpdas.h"

CCache* Cache = 0;

void
CCache::SaveCache()
{
	std::string path = getenv("HOME");
	path.append("/.mpdascache");
	remove(path.c_str());
	std::ofstream ofs(path.c_str());
	if(!_entries.size()) {
		remove(path.c_str());
		return;
	}

	for(unsigned int i = 0; i < _entries.size(); i++) {
		centry_t* entry = _entries[i];
		if(entry->album)
			ofs << true << "\n";
		ofs << entry->artist << "\n";
		ofs << entry->title << "\n";
		ofs << entry->time << "\n";
		ofs << entry->starttime;
		if(entry->album)
			ofs << "\n" << entry->album;
		if(i+1 == _entries.size())
			ofs.flush();
		else
			ofs << std::endl;
	}
	ofs.close();
}

void
CCache::LoadCache()
{
	int length;
	std::string path = getenv("HOME");
	path.append("/.mpdascache");
	std::ifstream ifs(path.c_str(), std::ios::in|std::ios::binary);

	ifs.seekg (0, std::ios::end);
	length = ifs.tellg();
	ifs.seekg (0, std::ios::beg);

	while(ifs.good()) {
		if(length == ifs.tellg())
			break;
		std::string artist, album, title;
		bool gotalbum = false;
		int time;
		time_t starttime;

		ifs >> gotalbum;
		ifs.ignore(1);
		ifs >> artist;
		ifs >> title;
		ifs >> time;
		ifs.ignore(1);
		ifs >> starttime;
		ifs.ignore(1);
		if(gotalbum)
			getline(ifs, album);
		AddToCache(time, artist, title, album, starttime, true);
	}

	ifs.close();
	remove(path.c_str());
}

void
CCache::WorkCache()
{
	if(_failtime && time(NULL) - _failtime < 300) {
		return;
	}
	_failtime = 0;
	while(_entries.size()) {
		if(AudioScrobbler->Scrobble(_entries.front())) {
			curl_free((void*)_entries.front()->artist);
			curl_free((void*)_entries.front()->title);
			if(_entries.front()->album)
				curl_free((void*)_entries.front()->album);
			delete _entries.front();
			_entries.erase(_entries.begin());
		}
		else {
			eprintf("%s", "Error scrobbling. Trying again in 5 minutes.");
			_failtime = time(NULL);
			AudioScrobbler->Failure();
			break;
		}
		sleep(1);
	}
	SaveCache();
}

void
CCache::AddToCache(int time, std::string artist, std::string title, std::string album, time_t starttime, bool escaped = false)
{
	centry_t* entry = new centry_t;
	bzero(entry, sizeof(centry_t));

	entry->time = time;
	if(!escaped) {
		entry->artist = (char*)curl_escape(artist.c_str(), 0);
		entry->title = (char*)curl_escape(title.c_str(), 0);
		if(album.size())
			entry->album = (char*)curl_escape(album.c_str(), 0);
	} else {
		entry->artist = new char[artist.size()+1];
		strcpy(entry->artist, artist.c_str());
		entry->title = new char[title.size()+1];
		strcpy(entry->title, title.c_str());
		if(album.size()) {
			entry->album = new char[album.size()+1];
			strcpy(entry->album, album.c_str());
		}
	}
	entry->starttime = starttime;
	_entries.push_back(entry);
	SaveCache();
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace iox
{
namespace concurrent
{
template <class ValueType, uint32_t CapacityValue>
SoFi<ValueType, CapacityValue>::SoFi() noexcept
{
}

template <class ValueType, uint32_t CapacityValue>
uint64_t SoFi<ValueType, CapacityValue>::capacity() const noexcept
{
    return m_size - INTERNAL_SIZE_ADD_ON;
}

template <class ValueType, uint32_t CapacityValue>
uint64_t SoFi<ValueType, CapacityValue>::size() const noexcept
{
    uint64_t readPosition;
    uint64_t writePosition;
    do
    {
        readPosition = m_readPosition.load(std::memory_order_relaxed);
        writePosition = m_writePosition.load(std::memory_order_relaxed);
    } while (m_writePosition.load(std::memory_order_relaxed) != writePosition
             || m_readPosition.load(std::memory_order_relaxed) != readPosition);

    return writePosition - readPosition;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::resize(const uint32_t newSize) noexcept
{
    uint64_t newInternalSize = newSize + INTERNAL_SIZE_ADD_ON;
    if (empty() && (newInternalSize <= INTERNAL_SOFI_SIZE))
    {
        m_size = newInternalSize;

        m_readPosition.store(0u, std::memory_order_release);
        m_writePosition.store(0u, std::memory_order_release);

        return true;
    }

    return false;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::empty() const noexcept
{
    uint64_t currentReadPosition;
    bool isEmpty;

    do
    {
        /// @todo read before write since the writer increments the aba counter!!!
        /// @todo write doc with example!!!
        currentReadPosition = m_readPosition.load(std::memory_order_acquire);
        uint64_t currentWritePosition = m_writePosition.load(std::memory_order_acquire);

        isEmpty = (currentWritePosition == currentReadPosition);
        // we need compare without exchange
    } while (!(currentReadPosition == m_readPosition.load(std::memory_order_acquire)));

    return isEmpty;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::pop(ValueType& valueOut) noexcept
{
    return popIf(valueOut, [](ValueType) { return true; });
}

template <class ValueType, uint32_t CapacityValue>
template <typename Verificator_T>
inline bool SoFi<ValueType, CapacityValue>::popIf(ValueType& valueOut, const Verificator_T& verificator) noexcept
{
    uint64_t currentReadPosition = m_readPosition.load(std::memory_order_acquire);
    uint64_t nextReadPosition;

    bool popWasSuccessful{true};
    do
    {
        if (currentReadPosition == m_writePosition.load(std::memory_order_acquire))
        {
            nextReadPosition = currentReadPosition;
            popWasSuccessful = false;
        }
        else
        {
            // we use memcpy here, since the copy assignment is not thread safe in general (we might have an overflow in
            // the push thread and invalidates the object while the copy is running and therefore works on an
            // invalid object); memcpy is also not thread safe, but we discard the object anyway and read it
            // again if its overwritten in between; this is only relevant for types larger than pointer size
            // assign the user data
            std::memcpy(&valueOut, &m_data[static_cast<int32_t>(currentReadPosition) % m_size], sizeof(ValueType));

            /// @brief first we need to peak valueOut if it is fitting the condition and then we have to verify
            ///        if valueOut is not am invalid object, this could be the case if the read position has
            ///        changed
            if (m_readPosition.load(std::memory_order_relaxed) == currentReadPosition && verificator(valueOut) == false)
            {
                popWasSuccessful = false;
            }
            else
            {
                nextReadPosition = currentReadPosition + 1U;
                popWasSuccessful = true;
            }
        }

        // compare and swap
        // if(m_readPosition == currentReadPosition)
        //     m_readPosition = l_next_aba_read_pos
        // else
        //     currentReadPosition = m_readPosition
        // Assign m_aba_read_p to next readable location
    } while (!m_readPosition.compare_exchange_weak(
        currentReadPosition, nextReadPosition, std::memory_order_acq_rel, std::memory_order_acquire));

    return popWasSuccessful;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::push(const ValueType& valueOut, ValueType& f_paramOut_r) noexcept
{
    constexpr bool OVERFLOW{false};

    uint64_t currentWritePosition = m_writePosition.load(std::memory_order_relaxed);
    uint64_t nextWritePosition = currentWritePosition + 1U;

    m_data[static_cast<int32_t>(currentWritePosition) % m_size] = valueOut;
    m_writePosition.store(nextWritePosition, std::memory_order_release);

    uint64_t currentReadPosition = m_readPosition.load(std::memory_order_acquire);

    // check if there is a free position for the next push
    if (nextWritePosition < currentReadPosition + m_size)
    {
        return !OVERFLOW;
    }

    // this is an overflow situation, which means that the next push has no free position, therefore the oldest value
    // needs to be passed back to the caller

    uint64_t nextReadPosition = currentReadPosition + 1U;

    // we need to update the read position
    // a) it works, then we need to pass the overflow value back
    // b) it doesn't work, which means that the pop thread already took the value in the meantime an no further action
    // is required
    // memory order success is memory_order_acq_rel
    //   - this is to prevent the reordering of m_writePosition.store(...) after the increment of the m_readPosition
    //     - in case of an overflow, this might result in the pop thread getting one element less than the capacity of
    //       the SoFi if the push thread is suspended in between this two statements
    //     - it's still possible to get more elements than the capacity, but this is an inherent issue with concurrent
    //       queues and cannot be prevented since there can always be a push during a pop operation
    //   - another issue might be that two consecutive pushes (not concurrent) happen on different CPU cores without
    //     synchronization, then the memory also needs to be synchronized for the overflow case
    // memory order failure is memory_order_relaxed since there is no further synchronization needed if there is no
    // overflow
    if (m_readPosition.compare_exchange_strong(
            currentReadPosition, nextReadPosition, std::memory_order_acq_rel, std::memory_order_relaxed))
    {
        std::memcpy(&f_paramOut_r, &m_data[static_cast<int32_t>(currentReadPosition) % m_size], sizeof(ValueType));
        return OVERFLOW;
    }

    return !OVERFLOW;
}

} // namespace concurrent
} // namespace iox
<commit_msg>iox-#32 fix compiler error in sofi.inl:142<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace iox
{
namespace concurrent
{
template <class ValueType, uint32_t CapacityValue>
SoFi<ValueType, CapacityValue>::SoFi() noexcept
{
}

template <class ValueType, uint32_t CapacityValue>
uint64_t SoFi<ValueType, CapacityValue>::capacity() const noexcept
{
    return m_size - INTERNAL_SIZE_ADD_ON;
}

template <class ValueType, uint32_t CapacityValue>
uint64_t SoFi<ValueType, CapacityValue>::size() const noexcept
{
    uint64_t readPosition;
    uint64_t writePosition;
    do
    {
        readPosition = m_readPosition.load(std::memory_order_relaxed);
        writePosition = m_writePosition.load(std::memory_order_relaxed);
    } while (m_writePosition.load(std::memory_order_relaxed) != writePosition
             || m_readPosition.load(std::memory_order_relaxed) != readPosition);

    return writePosition - readPosition;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::resize(const uint32_t newSize) noexcept
{
    uint64_t newInternalSize = newSize + INTERNAL_SIZE_ADD_ON;
    if (empty() && (newInternalSize <= INTERNAL_SOFI_SIZE))
    {
        m_size = newInternalSize;

        m_readPosition.store(0u, std::memory_order_release);
        m_writePosition.store(0u, std::memory_order_release);

        return true;
    }

    return false;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::empty() const noexcept
{
    uint64_t currentReadPosition;
    bool isEmpty;

    do
    {
        /// @todo read before write since the writer increments the aba counter!!!
        /// @todo write doc with example!!!
        currentReadPosition = m_readPosition.load(std::memory_order_acquire);
        uint64_t currentWritePosition = m_writePosition.load(std::memory_order_acquire);

        isEmpty = (currentWritePosition == currentReadPosition);
        // we need compare without exchange
    } while (!(currentReadPosition == m_readPosition.load(std::memory_order_acquire)));

    return isEmpty;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::pop(ValueType& valueOut) noexcept
{
    return popIf(valueOut, [](ValueType) { return true; });
}

template <class ValueType, uint32_t CapacityValue>
template <typename Verificator_T>
inline bool SoFi<ValueType, CapacityValue>::popIf(ValueType& valueOut, const Verificator_T& verificator) noexcept
{
    uint64_t currentReadPosition = m_readPosition.load(std::memory_order_acquire);
    uint64_t nextReadPosition;

    bool popWasSuccessful{true};
    do
    {
        if (currentReadPosition == m_writePosition.load(std::memory_order_acquire))
        {
            nextReadPosition = currentReadPosition;
            popWasSuccessful = false;
        }
        else
        {
            // we use memcpy here, since the copy assignment is not thread safe in general (we might have an overflow in
            // the push thread and invalidates the object while the copy is running and therefore works on an
            // invalid object); memcpy is also not thread safe, but we discard the object anyway and read it
            // again if its overwritten in between; this is only relevant for types larger than pointer size
            // assign the user data
            std::memcpy(&valueOut, &m_data[static_cast<int32_t>(currentReadPosition) % m_size], sizeof(ValueType));

            /// @brief first we need to peak valueOut if it is fitting the condition and then we have to verify
            ///        if valueOut is not am invalid object, this could be the case if the read position has
            ///        changed
            if (m_readPosition.load(std::memory_order_relaxed) == currentReadPosition && verificator(valueOut) == false)
            {
                popWasSuccessful = false;
            }
            else
            {
                nextReadPosition = currentReadPosition + 1U;
                popWasSuccessful = true;
            }
        }

        // compare and swap
        // if(m_readPosition == currentReadPosition)
        //     m_readPosition = l_next_aba_read_pos
        // else
        //     currentReadPosition = m_readPosition
        // Assign m_aba_read_p to next readable location
    } while (!m_readPosition.compare_exchange_weak(
        currentReadPosition, nextReadPosition, std::memory_order_acq_rel, std::memory_order_acquire));

    return popWasSuccessful;
}

template <class ValueType, uint32_t CapacityValue>
bool SoFi<ValueType, CapacityValue>::push(const ValueType& valueOut, ValueType& f_paramOut_r) noexcept
{
    constexpr bool SOFI_OVERFLOW{false};

    uint64_t currentWritePosition = m_writePosition.load(std::memory_order_relaxed);
    uint64_t nextWritePosition = currentWritePosition + 1U;

    m_data[static_cast<int32_t>(currentWritePosition) % m_size] = valueOut;
    m_writePosition.store(nextWritePosition, std::memory_order_release);

    uint64_t currentReadPosition = m_readPosition.load(std::memory_order_acquire);

    // check if there is a free position for the next push
    if (nextWritePosition < currentReadPosition + m_size)
    {
        return !SOFI_OVERFLOW;
    }

    // this is an overflow situation, which means that the next push has no free position, therefore the oldest value
    // needs to be passed back to the caller

    uint64_t nextReadPosition = currentReadPosition + 1U;

    // we need to update the read position
    // a) it works, then we need to pass the overflow value back
    // b) it doesn't work, which means that the pop thread already took the value in the meantime an no further action
    // is required
    // memory order success is memory_order_acq_rel
    //   - this is to prevent the reordering of m_writePosition.store(...) after the increment of the m_readPosition
    //     - in case of an overflow, this might result in the pop thread getting one element less than the capacity of
    //       the SoFi if the push thread is suspended in between this two statements
    //     - it's still possible to get more elements than the capacity, but this is an inherent issue with concurrent
    //       queues and cannot be prevented since there can always be a push during a pop operation
    //   - another issue might be that two consecutive pushes (not concurrent) happen on different CPU cores without
    //     synchronization, then the memory also needs to be synchronized for the overflow case
    // memory order failure is memory_order_relaxed since there is no further synchronization needed if there is no
    // overflow
    if (m_readPosition.compare_exchange_strong(
            currentReadPosition, nextReadPosition, std::memory_order_acq_rel, std::memory_order_relaxed))
    {
        std::memcpy(&f_paramOut_r, &m_data[static_cast<int32_t>(currentReadPosition) % m_size], sizeof(ValueType));
        return SOFI_OVERFLOW;
    }

    return !SOFI_OVERFLOW;
}

} // namespace concurrent
} // namespace iox
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

struct point {
	float x;
	float y;

	point(float xIn, float yIn) : x(xIn), y(yIn) { }
};

// The z-value of the cross product of segments
// (a, b) and (a, c). Positive means c is ccw
// from (a, b), negative cw. Zero means its collinear.
float ccw(const point& a, const point& b, const point& c) {
	return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}

// Returns true if a is lexicographically before b.
bool isLeftOf(const point& a, const point& b) {
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

// Used to sort points in ccw order about a pivot.
struct ccwSorter {
	const point& pivot;

	ccwSorter(const point& inPivot) : pivot(inPivot) { }

	bool operator()(const point& a, const point& b) {
		return ccw(pivot, a, b) < 0;
	}
};

// The length of segment (a, b).
float len(const point& a, const point& b) {
	return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
}

// The unsigned distance of p from segment (a, b).
float dist(const point& a, const point& b, const point& p) {
	return fabs((b.x - a.x) * (a.y - p.y) - (b.y - a.y) * (a.x - p.x)) / len(a, b);
}

// Returns the index of the farthest point from segment (a, b).
size_t getFarthest(const point& a, const point& b, const vector<point>& v) {
	size_t idxMax = 0;
	float distMax = dist(a, b, v[idxMax]);

	for (size_t i = 1; i < v.size(); ++i) {
		float distCurr = dist(a, b, v[i]);
		if (distCurr > distMax) {
			idxMax = i;
			distMax = distCurr;
		}
	}

	return idxMax;
}

// The gift-wrapping algorithm for convex hull.
// https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
vector<point> giftWrapping(const vector<point>& v) {
	// Start with the leftmost point.
	size_t startIdx = min_element(v.begin(), v.end(), isLeftOf) - v.begin();
	size_t hIdx = startIdx;

	vector<point> hull;
	do {
		// Add our current point to the hull.
		hull.push_back(v[hIdx]);

		// Find the index of the input point that is farthest
		// ccw from our last hull point.
		ccwSorter isCcw(v[hIdx]);
		size_t endIdx = 0;
		for (size_t i = 1; i < v.size(); ++i) {
			if ((endIdx == hIdx) || isCcw(v[endIdx], v[i])) {
				endIdx = i;
			}
		}

		// Make that our new
		hIdx = endIdx;
	} while (hIdx != startIdx);

	return hull;
}

// The Graham scan algorithm for convex hull.
// https://en.wikipedia.org/wiki/Graham_scan
vector<point> GrahamScan(vector<point> v) {
	// Put our leftmost point at index 0
	swap(v[0], *min_element(v.begin(), v.end(), isLeftOf));

	// Sort the rest of the points in counter-clockwise order
	// from our leftmost point.
	sort(v.begin() + 1, v.end(), ccwSorter(v[0]));

	// Add our first three points to the hull.
	vector<point> hull;
	auto it = v.begin();
	hull.push_back(*it++);
	hull.push_back(*it++);
	hull.push_back(*it++);

	while (it != v.end()) {
		// Pop off any points that make a convex angle with *it
		while (ccw(*(hull.rbegin() + 1), *(hull.rbegin()), *it) >= 0) {
			hull.pop_back();
		}
		hull.push_back(*it++);
	}

	return hull;
}

// The monotone chain algorithm for convex hull.
vector<point> monotoneChain(vector<point> v) {
	// Sort out points in lexicographic order.
	sort(v.begin(), v.end(), isLeftOf);

	// Find the lower half of the convex hull.
	vector<point> lower;
	for (auto it = v.begin(); it != v.end(); ++it) {
		// Pop off any points that make a convex angle with *it
		while (lower.size() >= 2 && ccw(*(lower.rbegin() + 1), *(lower.rbegin()), *it) >= 0) {
			lower.pop_back();
		}
		lower.push_back(*it);
	}

	// Find the upper half of the convex hull.
	vector<point> upper;
	for (auto it = v.rbegin(); it != v.rend(); ++it) {
		// Pop off any points that make a convex angle with *it
		while (upper.size() >= 2 && ccw(*(upper.rbegin() + 1), *(upper.rbegin()), *it) >= 0) {
			upper.pop_back();
		}
		upper.push_back(*it);
	}

	vector<point> hull;
	hull.insert(hull.end(), lower.begin(), lower.end());
	hull.insert(hull.end(), upper.begin() + 1, upper.end() - 1);
	return hull;
}

// Recursive call of the quickhull algorithm.
void quickHull(const vector<point>& v, const point& a, const point& b,
			   vector<point>& hull) {
	if (v.empty()) {
		return;
	}

	point f = v[getFarthest(a, b, v)];

	// Collect points to the left of segment (a, f)
	vector<point> left;
	for (auto p : v) {
		if (ccw(a, f, p) > 0) {
			left.push_back(p);
		}
	}
	quickHull(left, a, f, hull);

	// Add f to the hull
	hull.push_back(f);

	// Collect points to the left of segment (f, b)
	vector<point> right;
	for (auto p : v) {
		if (ccw(f, b, p) > 0) {
			right.push_back(p);
		}
	}
	quickHull(right, f, b, hull);
}

// QuickHull algorithm.
// https://en.wikipedia.org/wiki/QuickHull
vector<point> quickHull(const vector<point>& v) {
	vector<point> hull;

	// Start with the leftmost and rightmost points.
	point a = *min_element(v.begin(), v.end(), isLeftOf);
	point b = *max_element(v.begin(), v.end(), isLeftOf);

	// Split the points on either side of segment (a, b)
	vector<point> left, right;
	for (auto p : v) {
		ccw(a, b, p) > 0 ? left.push_back(p) : right.push_back(p);
	}

	// Be careful to add points to the hull
	// in the correct order. Add our leftmost point.
	hull.push_back(a);

	// Add hull points from the left (top)
	quickHull(left, a, b, hull);

	// Add our rightmost point
	hull.push_back(b);

	// Add hull points from the right (bottom)
	quickHull(right, b, a, hull);

	return hull;
}

vector<point> getPoints() {
	vector<point> v;

	const float lo = -100.0;
	const float hi = 100.0;

	for (int i = 0; i < 100; ++i) {
		float x = lo +
			static_cast<float>(
				rand()) / static_cast<float>(RAND_MAX / (hi - lo));

		float y = lo +
			static_cast<float>(
				rand()) / static_cast<float>(RAND_MAX / (hi - lo));

		v.push_back(point(x, y));
	}

	return v;
}

void print(const vector<point>& v) {
	for (auto p : v) {
		cout << p.x << ", " << p.y << endl;
	}
}

int main() {
	vector<point> v = getPoints();

	vector<point> h = quickHull(v);
	cout << "quickHull point count: " << h.size() << endl;
	print(h);

 	h = giftWrapping(v);
	cout << endl << "giftWrapping point count: " << h.size() << endl;
	print(h);

	h = monotoneChain(v);
	cout << endl << "monotoneChain point count: " << h.size() << endl;
	print(h);

	h = GrahamScan(v);
	cout << endl << "GrahamScan point count: " << h.size() << endl;
	print(h);

	return 0;
}
<commit_msg>add comments, fix tabs<commit_after>// Implementations of various convex hull algorithms
// using the C++ Standard Library.
// For clarity, the implementations do not check for
// duplicate or collinear points.

#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

struct point {
	float x;
	float y;

	point(float xIn, float yIn) : x(xIn), y(yIn) { }
};

// The z-value of the cross product of segments
// (a, b) and (a, c). Positive means c is ccw
// from (a, b), negative cw. Zero means its collinear.
float ccw(const point& a, const point& b, const point& c) {
	return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}

// Returns true if a is lexicographically before b.
bool isLeftOf(const point& a, const point& b) {
	return (a.x < b.x || (a.x == b.x && a.y < b.y));
}

// Used to sort points in ccw order about a pivot.
struct ccwSorter {
	const point& pivot;

	ccwSorter(const point& inPivot) : pivot(inPivot) { }

	bool operator()(const point& a, const point& b) {
		return ccw(pivot, a, b) < 0;
	}
};

// The length of segment (a, b).
float len(const point& a, const point& b) {
	return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
}

// The unsigned distance of p from segment (a, b).
float dist(const point& a, const point& b, const point& p) {
	return fabs((b.x - a.x) * (a.y - p.y) - (b.y - a.y) * (a.x - p.x)) / len(a, b);
}

// Returns the index of the farthest point from segment (a, b).
size_t getFarthest(const point& a, const point& b, const vector<point>& v) {
	size_t idxMax = 0;
	float distMax = dist(a, b, v[idxMax]);

	for (size_t i = 1; i < v.size(); ++i) {
		float distCurr = dist(a, b, v[i]);
		if (distCurr > distMax) {
			idxMax = i;
			distMax = distCurr;
		}
	}

	return idxMax;
}

// The gift-wrapping algorithm for convex hull.
// https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
vector<point> giftWrapping(const vector<point>& v) {
	// Start with the leftmost point.
	size_t startIdx = min_element(v.begin(), v.end(), isLeftOf) - v.begin();
	size_t hIdx = startIdx;

	vector<point> hull;
	do {
		// Add our current point to the hull.
		hull.push_back(v[hIdx]);

		// Find the index of the input point that is farthest
		// ccw from our last hull point.
		ccwSorter isCcw(v[hIdx]);
		size_t endIdx = 0;
		for (size_t i = 1; i < v.size(); ++i) {
			if ((endIdx == hIdx) || isCcw(v[endIdx], v[i])) {
				endIdx = i;
			}
		}

		// Make that our new
		hIdx = endIdx;
	} while (hIdx != startIdx);

	return hull;
}

// The Graham scan algorithm for convex hull.
// https://en.wikipedia.org/wiki/Graham_scan
vector<point> GrahamScan(vector<point> v) {
	// Put our leftmost point at index 0
	swap(v[0], *min_element(v.begin(), v.end(), isLeftOf));

	// Sort the rest of the points in counter-clockwise order
	// from our leftmost point.
	sort(v.begin() + 1, v.end(), ccwSorter(v[0]));

	// Add our first three points to the hull.
	vector<point> hull;
	auto it = v.begin();
	hull.push_back(*it++);
	hull.push_back(*it++);
	hull.push_back(*it++);

	while (it != v.end()) {
		// Pop off any points that make a convex angle with *it
		while (ccw(*(hull.rbegin() + 1), *(hull.rbegin()), *it) >= 0) {
			hull.pop_back();
		}
		hull.push_back(*it++);
	}

	return hull;
}

// The monotone chain algorithm for convex hull.
vector<point> monotoneChain(vector<point> v) {
	// Sort out points in lexicographic order.
	sort(v.begin(), v.end(), isLeftOf);

	// Find the lower half of the convex hull.
	vector<point> lower;
	for (auto it = v.begin(); it != v.end(); ++it) {
		// Pop off any points that make a convex angle with *it
		while (lower.size() >= 2 && ccw(*(lower.rbegin() + 1), *(lower.rbegin()), *it) >= 0) {
			lower.pop_back();
		}
		lower.push_back(*it);
	}

	// Find the upper half of the convex hull.
	vector<point> upper;
	for (auto it = v.rbegin(); it != v.rend(); ++it) {
		// Pop off any points that make a convex angle with *it
		while (upper.size() >= 2 && ccw(*(upper.rbegin() + 1), *(upper.rbegin()), *it) >= 0) {
			upper.pop_back();
		}
		upper.push_back(*it);
	}

	vector<point> hull;
	hull.insert(hull.end(), lower.begin(), lower.end());
	hull.insert(hull.end(), upper.begin() + 1, upper.end() - 1);
	return hull;
}

// Recursive call of the quickhull algorithm.
void quickHull(const vector<point>& v, const point& a, const point& b,
			   vector<point>& hull) {
	if (v.empty()) {
		return;
	}

	point f = v[getFarthest(a, b, v)];

	// Collect points to the left of segment (a, f)
	vector<point> left;
	for (auto p : v) {
		if (ccw(a, f, p) > 0) {
			left.push_back(p);
		}
	}
	quickHull(left, a, f, hull);

	// Add f to the hull
	hull.push_back(f);

	// Collect points to the left of segment (f, b)
	vector<point> right;
	for (auto p : v) {
		if (ccw(f, b, p) > 0) {
			right.push_back(p);
		}
	}
	quickHull(right, f, b, hull);
}

// QuickHull algorithm.
// https://en.wikipedia.org/wiki/QuickHull
vector<point> quickHull(const vector<point>& v) {
	vector<point> hull;

	// Start with the leftmost and rightmost points.
	point a = *min_element(v.begin(), v.end(), isLeftOf);
	point b = *max_element(v.begin(), v.end(), isLeftOf);

	// Split the points on either side of segment (a, b)
	vector<point> left, right;
	for (auto p : v) {
		ccw(a, b, p) > 0 ? left.push_back(p) : right.push_back(p);
	}

	// Be careful to add points to the hull
	// in the correct order. Add our leftmost point.
	hull.push_back(a);

	// Add hull points from the left (top)
	quickHull(left, a, b, hull);

	// Add our rightmost point
	hull.push_back(b);

	// Add hull points from the right (bottom)
	quickHull(right, b, a, hull);

	return hull;
}

vector<point> getPoints() {
	vector<point> v;

	const float lo = -100.0;
	const float hi = 100.0;

	for (int i = 0; i < 100; ++i) {
		float x = lo +
			static_cast<float>(
				rand()) / static_cast<float>(RAND_MAX / (hi - lo));

		float y = lo +
			static_cast<float>(
				rand()) / static_cast<float>(RAND_MAX / (hi - lo));

		v.push_back(point(x, y));
	}

	return v;
}

void print(const vector<point>& v) {
	for (auto p : v) {
		cout << p.x << ", " << p.y << endl;
	}
}

int main() {
	vector<point> v = getPoints();

	vector<point> h = quickHull(v);
	cout << "quickHull point count: " << h.size() << endl;
	print(h);

 	h = giftWrapping(v);
	cout << endl << "giftWrapping point count: " << h.size() << endl;
	print(h);

	h = monotoneChain(v);
	cout << endl << "monotoneChain point count: " << h.size() << endl;
	print(h);

	h = GrahamScan(v);
	cout << endl << "GrahamScan point count: " << h.size() << endl;
	print(h);

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "utility.h"

 #include <omp.h>

Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY)
{
  Rect expandedRegion = Rect(original);

  float halfX = round((float) expandXPixels / 2.0);
  float halfY = round((float) expandYPixels / 2.0);
  expandedRegion.x = expandedRegion.x - halfX;
  expandedRegion.width =  expandedRegion.width + expandXPixels;
  expandedRegion.y = expandedRegion.y - halfY;
  expandedRegion.height =  expandedRegion.height + expandYPixels;

  if (expandedRegion.x < 0)
    expandedRegion.x = 0;
  if (expandedRegion.y < 0)
    expandedRegion.y = 0;
  if (expandedRegion.x + expandedRegion.width > maxX)
    expandedRegion.width = maxX - expandedRegion.x;
  if (expandedRegion.y + expandedRegion.height > maxY)
    expandedRegion.height = maxY - expandedRegion.y;

  return expandedRegion;
}

Mat drawImageDashboard(vector<Mat> images, int imageType, int numColumns)
{
    int numRows = ceil((float) images.size() / (float) numColumns);

    Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType);

      for (int i = 0; i < numColumns * numRows; i++)
      {
	if (i < images.size())
	  images[i].copyTo(dashboard(Rect((i%numColumns) * images[i].cols, floor((float) i/numColumns) * images[i].rows, images[i].cols, images[i].rows)));
	else
	{
	  Mat black = Mat::zeros(images[0].size(), imageType);
	  black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows)));
	}
      }

      return dashboard;
}

Mat addLabel(Mat input, string label)
{
  const int border_size = 1;
  const Scalar border_color(0,0,255);
  const int extraHeight = 20;
  const Scalar bg(222,222,222);
  const Scalar fg(0,0,0);

  Rect destinationRect(border_size, extraHeight, input.cols, input.rows);
  Mat newImage(Size(input.cols + (border_size), input.rows + extraHeight + (border_size )), input.type());
  input.copyTo(newImage(destinationRect));

  cout << " Adding label " << label << endl;
  if (input.type() == CV_8U)
    cvtColor(newImage, newImage, CV_GRAY2BGR);

  rectangle(newImage, Point(0,0), Point(input.cols, extraHeight), bg, CV_FILLED);
  putText(newImage, label, Point(5, extraHeight - 5), CV_FONT_HERSHEY_PLAIN  , 0.7, fg);

  rectangle(newImage, Point(0,0), Point(newImage.cols - 1, newImage.rows -1), border_color, border_size);

  return newImage;
}

void drawAndWait(cv::Mat* frame)
{
  cv::imshow("Temp Window", *frame);

  while (cv::waitKey(50) == -1)
  {
      // loop
  }

  cv::destroyWindow("Temp Window");
}

void displayImage(Config* config, string windowName, cv::Mat frame)
{
  if (config->debugShowImages)
    imshow(windowName, frame);
}

vector<Mat> produceThresholds(const Mat img_gray, Config* config)
{
  const int THRESHOLD_COUNT = 10;
  //Mat img_equalized = equalizeBrightness(img_gray);

  timespec startTime;
  getTime(&startTime);

  vector<Mat> thresholds;

  //#pragma omp parallel for
  for (int i = 0; i < THRESHOLD_COUNT; i++)
    thresholds.push_back(Mat(img_gray.size(), CV_8U));

  for (int i = 0; i < THRESHOLD_COUNT; i++)
  {

    if (i <= 2)		//0-2
    {
      int k = ((i%3) * 5) + 7;  // 7, 12, 17
      if (k==12) k = 13;	// change 12 to 13
      //#pragma omp ordered
      adaptiveThreshold(img_gray, thresholds[i], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , k, 3);
    }
    else if (i <= 6)	//3-6
    {
      int k = i%2;		// 0 or 1
      int win = 18 + (k * 4);	// 18 or 22
      //#pragma omp ordered
      NiblackSauvolaWolfJolion (img_gray, thresholds[i], WOLFJOLION, win, win, 0.05 + (k * 0.35));
      bitwise_not(thresholds[i], thresholds[i]);

    }
    else if (i <= 9)	//7-9
    {
      int k = (i%3) + 1;	// 1,2,3
      //#pragma omp ordered
      NiblackSauvolaWolfJolion (img_gray, thresholds[i], SAUVOLA, 12, 12, 0.18 * k);
      bitwise_not(thresholds[i], thresholds[i]);

    }

  }

  if (config->debugTiming)
  {
    timespec endTime;
    getTime(&endTime);
    cout << "  -- Produce Threshold Time: " << diffclock(startTime, endTime) << "ms." << endl;
  }

  return thresholds;
  //threshold(img_equalized, img_threshold, 100, 255, THRESH_BINARY);

}

Mat equalizeBrightness(Mat img)
{

  // Divide the image by its morphologically closed counterpart
  Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19));
  Mat closed;
  morphologyEx(img, closed, MORPH_CLOSE, kernel);

  img.convertTo(img, CV_32FC1); // divide requires floating-point
  divide(img, closed, img, 1, CV_32FC1);
  normalize(img, img, 0, 255, NORM_MINMAX);
  img.convertTo(img, CV_8U); // convert back to unsigned int

  return img;
}

void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness)
{

  Point2f rect_points[4];
  rect.points( rect_points );
  for( int j = 0; j < 4; j++ )
    line( *img, rect_points[j], rect_points[(j+1)%4], color, thickness, 8 );

}

void fillMask(Mat img, const Mat mask, Scalar color)
{
  for (int row = 0; row < img.rows; row++)
  {
    for (int col = 0; col < img.cols; col++)
    {
      int m = (int) mask.at<uchar>(row, col);

      if (m)
      {
	for (int z = 0; z < 3; z++)
	{
	  int prevVal = img.at<Vec3b>(row, col)[z];
	  img.at<Vec3b>(row, col)[z] = ((int) color[z]) | prevVal;
	}
      }

    }
  }
}

void drawX(Mat img, Rect rect, Scalar color, int thickness)
{
  Point tl(rect.x, rect.y);
  Point tr(rect.x + rect.width, rect.y);
  Point bl(rect.x, rect.y + rect.height);
  Point br(rect.x + rect.width, rect.y + rect.height);

  line(img, tl, br, color, thickness);
  line(img, bl, tr, color, thickness);
}

double distanceBetweenPoints(Point p1, Point p2)
{
  float asquared = (p2.x - p1.x)*(p2.x - p1.x);
  float bsquared = (p2.y - p1.y)*(p2.y - p1.y);

  return sqrt(asquared + bsquared);
}

float angleBetweenPoints(Point p1, Point p2)
{
    int deltaY = p2.y - p1.y;
    int deltaX = p2.x - p1.x;

    return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI);
}

Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight)
{
    float aspect = ((float) inputImg.cols) / ((float) inputImg.rows);

    if (maxWidth / aspect > maxHeight)
    {
	return Size(maxHeight * aspect, maxHeight);
    }
    else
    {
      return Size(maxWidth, maxWidth / aspect);
    }
}

LineSegment::LineSegment()
{
  init(0, 0, 0, 0);
}

LineSegment::LineSegment(Point p1, Point p2)
{
  init(p1.x, p1.y, p2.x, p2.y);
}
LineSegment::LineSegment(int x1, int y1, int x2, int y2)
{
  init(x1, y1, x2, y2);
}

void LineSegment::init(int x1, int y1, int x2, int y2)
{
  this->p1 = Point(x1, y1);
  this->p2 = Point(x2, y2);

    if (p2.x - p1.x == 0)
      this->slope = 0.00000000001;
    else
      this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x);

    this->length = distanceBetweenPoints(p1, p2);

    this->angle = angleBetweenPoints(p1, p2);
}

bool LineSegment::isPointBelowLine( Point tp ){
     return ((p2.x - p1.x)*(tp.y - p1.y) - (p2.y - p1.y)*(tp.x - p1.x)) > 0;
}

float LineSegment::getPointAt(float x)
{
  return slope * (x - p2.x) + p2.y;
}

Point LineSegment::closestPointOnSegmentTo(Point p)
{
  float top = (p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y)*(p2.y - p1.y);

  float bottom = distanceBetweenPoints(p2, p1);
  bottom = bottom * bottom;

  float u = top / bottom;

  float x = p1.x + u * (p2.x - p1.x);
  float y = p1.y + u * (p2.y - p1.y);

  return Point(x, y);
}

Point LineSegment::intersection(LineSegment line)
{
    float c1, c2;
    float intersection_X = -1, intersection_Y= -1;

    c1 = p1.y - slope * p1.x; // which is same as y2 - slope * x2

    c2 = line.p2.y - line.slope * line.p2.x; // which is same as y2 - slope * x2

    if( (slope - line.slope) == 0)
    {
        //std::cout << "No Intersection between the lines" << endl;
    }
    else if (p1.x == p2.x)
    {
      // Line1 is vertical
      return Point(p1.x, line.getPointAt(p1.x));
    }
    else if (line.p1.x == line.p2.x)
    {
	// Line2 is vertical
      return Point(line.p1.x, getPointAt(line.p1.x));
    }
    else
    {
        intersection_X = (c2 - c1) / (slope - line.slope);
        intersection_Y = slope * intersection_X + c1;

    }

    return Point(intersection_X, intersection_Y);

}

Point LineSegment::midpoint()
{
  // Handle the case where the line is vertical
  if (p1.x == p2.x)
  {
    float ydiff = p2.y-p1.y;
    float y = p1.y + (ydiff/2);
    return Point(p1.x, y);
  }
  float diff = p2.x - p1.x;
  float midX = ((float) p1.x) + (diff / 2);
  int midY = getPointAt(midX);

  return Point(midX, midY);
}

LineSegment LineSegment::getParallelLine(float distance)
{
    float diff_x = p2.x - p1.x;
    float diff_y = p2.y - p1.y;
    float angle = atan2( diff_x, diff_y);
    float dist_x = distance * cos(angle);
    float dist_y = -distance * sin(angle);

    int offsetX = (int)round(dist_x);
    int offsetY = (int)round(dist_y);

    LineSegment result(p1.x + offsetX, p1.y + offsetY,
		       p2.x + offsetX, p2.y + offsetY);

    return result;
}

<commit_msg>OpenMP is not yet supported on Mac OS X (clang)<commit_after>/*
 * Copyright (c) 2013 New Designs Unlimited, LLC
 * Opensource Automated License Plate Recognition [http://www.openalpr.com]
 *
 * This file is part of OpenAlpr.
 *
 * OpenAlpr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "utility.h"

#ifndef __APPLE__ // CLang++ does not have yet implementet OpenMP
#include <omp.h>
#endif

Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY)
{
  Rect expandedRegion = Rect(original);

  float halfX = round((float) expandXPixels / 2.0);
  float halfY = round((float) expandYPixels / 2.0);
  expandedRegion.x = expandedRegion.x - halfX;
  expandedRegion.width =  expandedRegion.width + expandXPixels;
  expandedRegion.y = expandedRegion.y - halfY;
  expandedRegion.height =  expandedRegion.height + expandYPixels;

  if (expandedRegion.x < 0)
    expandedRegion.x = 0;
  if (expandedRegion.y < 0)
    expandedRegion.y = 0;
  if (expandedRegion.x + expandedRegion.width > maxX)
    expandedRegion.width = maxX - expandedRegion.x;
  if (expandedRegion.y + expandedRegion.height > maxY)
    expandedRegion.height = maxY - expandedRegion.y;

  return expandedRegion;
}

Mat drawImageDashboard(vector<Mat> images, int imageType, int numColumns)
{
    int numRows = ceil((float) images.size() / (float) numColumns);

    Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType);

      for (int i = 0; i < numColumns * numRows; i++)
      {
	if (i < images.size())
	  images[i].copyTo(dashboard(Rect((i%numColumns) * images[i].cols, floor((float) i/numColumns) * images[i].rows, images[i].cols, images[i].rows)));
	else
	{
	  Mat black = Mat::zeros(images[0].size(), imageType);
	  black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows)));
	}
      }

      return dashboard;
}

Mat addLabel(Mat input, string label)
{
  const int border_size = 1;
  const Scalar border_color(0,0,255);
  const int extraHeight = 20;
  const Scalar bg(222,222,222);
  const Scalar fg(0,0,0);

  Rect destinationRect(border_size, extraHeight, input.cols, input.rows);
  Mat newImage(Size(input.cols + (border_size), input.rows + extraHeight + (border_size )), input.type());
  input.copyTo(newImage(destinationRect));

  cout << " Adding label " << label << endl;
  if (input.type() == CV_8U)
    cvtColor(newImage, newImage, CV_GRAY2BGR);

  rectangle(newImage, Point(0,0), Point(input.cols, extraHeight), bg, CV_FILLED);
  putText(newImage, label, Point(5, extraHeight - 5), CV_FONT_HERSHEY_PLAIN  , 0.7, fg);

  rectangle(newImage, Point(0,0), Point(newImage.cols - 1, newImage.rows -1), border_color, border_size);

  return newImage;
}

void drawAndWait(cv::Mat* frame)
{
  cv::imshow("Temp Window", *frame);

  while (cv::waitKey(50) == -1)
  {
      // loop
  }

  cv::destroyWindow("Temp Window");
}

void displayImage(Config* config, string windowName, cv::Mat frame)
{
  if (config->debugShowImages)
    imshow(windowName, frame);
}

vector<Mat> produceThresholds(const Mat img_gray, Config* config)
{
  const int THRESHOLD_COUNT = 10;
  //Mat img_equalized = equalizeBrightness(img_gray);

  timespec startTime;
  getTime(&startTime);

  vector<Mat> thresholds;

  //#pragma omp parallel for
  for (int i = 0; i < THRESHOLD_COUNT; i++)
    thresholds.push_back(Mat(img_gray.size(), CV_8U));

  for (int i = 0; i < THRESHOLD_COUNT; i++)
  {

    if (i <= 2)		//0-2
    {
      int k = ((i%3) * 5) + 7;  // 7, 12, 17
      if (k==12) k = 13;	// change 12 to 13
      //#pragma omp ordered
      adaptiveThreshold(img_gray, thresholds[i], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , k, 3);
    }
    else if (i <= 6)	//3-6
    {
      int k = i%2;		// 0 or 1
      int win = 18 + (k * 4);	// 18 or 22
      //#pragma omp ordered
      NiblackSauvolaWolfJolion (img_gray, thresholds[i], WOLFJOLION, win, win, 0.05 + (k * 0.35));
      bitwise_not(thresholds[i], thresholds[i]);

    }
    else if (i <= 9)	//7-9
    {
      int k = (i%3) + 1;	// 1,2,3
      //#pragma omp ordered
      NiblackSauvolaWolfJolion (img_gray, thresholds[i], SAUVOLA, 12, 12, 0.18 * k);
      bitwise_not(thresholds[i], thresholds[i]);

    }

  }

  if (config->debugTiming)
  {
    timespec endTime;
    getTime(&endTime);
    cout << "  -- Produce Threshold Time: " << diffclock(startTime, endTime) << "ms." << endl;
  }

  return thresholds;
  //threshold(img_equalized, img_threshold, 100, 255, THRESH_BINARY);

}

Mat equalizeBrightness(Mat img)
{

  // Divide the image by its morphologically closed counterpart
  Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19));
  Mat closed;
  morphologyEx(img, closed, MORPH_CLOSE, kernel);

  img.convertTo(img, CV_32FC1); // divide requires floating-point
  divide(img, closed, img, 1, CV_32FC1);
  normalize(img, img, 0, 255, NORM_MINMAX);
  img.convertTo(img, CV_8U); // convert back to unsigned int

  return img;
}

void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness)
{

  Point2f rect_points[4];
  rect.points( rect_points );
  for( int j = 0; j < 4; j++ )
    line( *img, rect_points[j], rect_points[(j+1)%4], color, thickness, 8 );

}

void fillMask(Mat img, const Mat mask, Scalar color)
{
  for (int row = 0; row < img.rows; row++)
  {
    for (int col = 0; col < img.cols; col++)
    {
      int m = (int) mask.at<uchar>(row, col);

      if (m)
      {
	for (int z = 0; z < 3; z++)
	{
	  int prevVal = img.at<Vec3b>(row, col)[z];
	  img.at<Vec3b>(row, col)[z] = ((int) color[z]) | prevVal;
	}
      }

    }
  }
}

void drawX(Mat img, Rect rect, Scalar color, int thickness)
{
  Point tl(rect.x, rect.y);
  Point tr(rect.x + rect.width, rect.y);
  Point bl(rect.x, rect.y + rect.height);
  Point br(rect.x + rect.width, rect.y + rect.height);

  line(img, tl, br, color, thickness);
  line(img, bl, tr, color, thickness);
}

double distanceBetweenPoints(Point p1, Point p2)
{
  float asquared = (p2.x - p1.x)*(p2.x - p1.x);
  float bsquared = (p2.y - p1.y)*(p2.y - p1.y);

  return sqrt(asquared + bsquared);
}

float angleBetweenPoints(Point p1, Point p2)
{
    int deltaY = p2.y - p1.y;
    int deltaX = p2.x - p1.x;

    return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI);
}

Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight)
{
    float aspect = ((float) inputImg.cols) / ((float) inputImg.rows);

    if (maxWidth / aspect > maxHeight)
    {
	return Size(maxHeight * aspect, maxHeight);
    }
    else
    {
      return Size(maxWidth, maxWidth / aspect);
    }
}

LineSegment::LineSegment()
{
  init(0, 0, 0, 0);
}

LineSegment::LineSegment(Point p1, Point p2)
{
  init(p1.x, p1.y, p2.x, p2.y);
}
LineSegment::LineSegment(int x1, int y1, int x2, int y2)
{
  init(x1, y1, x2, y2);
}

void LineSegment::init(int x1, int y1, int x2, int y2)
{
  this->p1 = Point(x1, y1);
  this->p2 = Point(x2, y2);

    if (p2.x - p1.x == 0)
      this->slope = 0.00000000001;
    else
      this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x);

    this->length = distanceBetweenPoints(p1, p2);

    this->angle = angleBetweenPoints(p1, p2);
}

bool LineSegment::isPointBelowLine( Point tp ){
     return ((p2.x - p1.x)*(tp.y - p1.y) - (p2.y - p1.y)*(tp.x - p1.x)) > 0;
}

float LineSegment::getPointAt(float x)
{
  return slope * (x - p2.x) + p2.y;
}

Point LineSegment::closestPointOnSegmentTo(Point p)
{
  float top = (p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y)*(p2.y - p1.y);

  float bottom = distanceBetweenPoints(p2, p1);
  bottom = bottom * bottom;

  float u = top / bottom;

  float x = p1.x + u * (p2.x - p1.x);
  float y = p1.y + u * (p2.y - p1.y);

  return Point(x, y);
}

Point LineSegment::intersection(LineSegment line)
{
    float c1, c2;
    float intersection_X = -1, intersection_Y= -1;

    c1 = p1.y - slope * p1.x; // which is same as y2 - slope * x2

    c2 = line.p2.y - line.slope * line.p2.x; // which is same as y2 - slope * x2

    if( (slope - line.slope) == 0)
    {
        //std::cout << "No Intersection between the lines" << endl;
    }
    else if (p1.x == p2.x)
    {
      // Line1 is vertical
      return Point(p1.x, line.getPointAt(p1.x));
    }
    else if (line.p1.x == line.p2.x)
    {
	// Line2 is vertical
      return Point(line.p1.x, getPointAt(line.p1.x));
    }
    else
    {
        intersection_X = (c2 - c1) / (slope - line.slope);
        intersection_Y = slope * intersection_X + c1;

    }

    return Point(intersection_X, intersection_Y);

}

Point LineSegment::midpoint()
{
  // Handle the case where the line is vertical
  if (p1.x == p2.x)
  {
    float ydiff = p2.y-p1.y;
    float y = p1.y + (ydiff/2);
    return Point(p1.x, y);
  }
  float diff = p2.x - p1.x;
  float midX = ((float) p1.x) + (diff / 2);
  int midY = getPointAt(midX);

  return Point(midX, midY);
}

LineSegment LineSegment::getParallelLine(float distance)
{
    float diff_x = p2.x - p1.x;
    float diff_y = p2.y - p1.y;
    float angle = atan2( diff_x, diff_y);
    float dist_x = distance * cos(angle);
    float dist_y = -distance * sin(angle);

    int offsetX = (int)round(dist_x);
    int offsetY = (int)round(dist_y);

    LineSegment result(p1.x + offsetX, p1.y + offsetY,
		       p2.x + offsetX, p2.y + offsetY);

    return result;
}

<|endoftext|>


<commit_before><commit_msg>remove needless friend declaration<commit_after><|endoftext|>


<commit_before><commit_msg>Be careful not to access a string out of bounds<commit_after><|endoftext|>


<commit_before><commit_msg>cid#1202755 Clarify with assert that new_size == 0 cannot happen<commit_after><|endoftext|>