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

#include <nvbio/basic/atomics.h>
#include <nvbio/basic/threads.h>

#ifdef WIN32

#include <windows.h>

namespace nvbio {

int32 atomic_increment(int32 volatile *value) { return InterlockedIncrement(reinterpret_cast<LONG volatile*>(value)); }
int64 atomic_increment(int64 volatile *value) { return InterlockedIncrement64(value); }

int32 atomic_decrement(int32 volatile *value) { return InterlockedDecrement(reinterpret_cast<LONG volatile*>(value)); }
int64 atomic_decrement(int64 volatile *value) { return InterlockedDecrement64(value); }

} // namespace nvbio

#endif

namespace nvbio {

int32 host_atomic_add(int32* value, const int32 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value += op;
    return *value;
}
uint32 host_atomic_add(uint32* value, const uint32 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value += op;
    return *value;
}
int64 host_atomic_add(int64* value, const int64 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value += op;
    return *value;
}
uint64 host_atomic_add(uint64* value, const uint64 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value += op;
    return *value;
}
int32 host_atomic_sub(int32* value, const int32 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value -= op;
    return *value;
}
uint32 host_atomic_sub(uint32* value, const uint32 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value -= op;
    return *value;
}

int64 host_atomic_sub(int64* value, const int64 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value -= op;
    return *value;
}
uint64 host_atomic_sub(uint64* value, const uint64 op)
{
    Mutex mutex;
    ScopedLock lock( &mutex );

    *value -= op;
    return *value;
}

} // namespace nvbio
<commit_msg>- fixed semantics of host atomics to match (fetch & add) device ones - used real atomics under GCC<commit_after>/*
 * nvbio
 * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the NVIDIA CORPORATION nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <nvbio/basic/atomics.h>
#include <nvbio/basic/threads.h>

#ifdef WIN32

#include <windows.h>

namespace nvbio {

int32 atomic_increment(int32 volatile *value) { return InterlockedIncrement(reinterpret_cast<LONG volatile*>(value)); }
int64 atomic_increment(int64 volatile *value) { return InterlockedIncrement64(value); }

int32 atomic_decrement(int32 volatile *value) { return InterlockedDecrement(reinterpret_cast<LONG volatile*>(value)); }
int64 atomic_decrement(int64 volatile *value) { return InterlockedDecrement64(value); }

} // namespace nvbio

#endif

namespace nvbio {

int32 host_atomic_add(int32* value, const int32 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_add( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const int32 old = *value;
    *value += op;
    return old;
#endif
}
uint32 host_atomic_add(uint32* value, const uint32 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_add( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const uint32 old = *value;
    *value += op;
    return old;
#endif
}
int64 host_atomic_add(int64* value, const int64 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_add( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const int64 old = *value;
    *value += op;
    return old;
#endif
}
uint64 host_atomic_add(uint64* value, const uint64 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_add( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const uint64 old = *value;
    *value += op;
    return old;
#endif
}
int32 host_atomic_sub(int32* value, const int32 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_sub( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const int32 old = *value;
    *value -= op;
    return old;
#endif
}
uint32 host_atomic_sub(uint32* value, const uint32 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_sub( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const uint32 old = *value;
    *value -= op;
    return old;
#endif
}

int64 host_atomic_sub(int64* value, const int64 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_sub( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const int64 old = *value;
    *value -= op;
    return old;
#endif
}
uint64 host_atomic_sub(uint64* value, const uint64 op)
{
#if defined(__GNUC__)
    return __atomic_fetch_sub( value, op, __ATOMIC_RELAXED );
#else
    Mutex mutex;
    ScopedLock lock( &mutex );

    const uint64 old = *value;
    *value -= op;
    return old;
#endif
}

} // namespace nvbio
<|endoftext|>


<commit_before>/*
    Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>

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

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

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

#include <QtTest>
#include <QtCore>
#include <qtest_kde.h>
#include <qtestevent.h>

#include "dynamictreemodel.h"
#include "../modeltest.h"
#include "../descendantentitiesproxymodel.h"
#include "proxymodeltest.h"

// #include "fakemonitor.h"

#include <QTreeView>

#include <kdebug.h>

using namespace Akonadi;

class DescendantEntitiesProxyModelTest : public ProxyModelTest
{
  Q_OBJECT
public:
  DescendantEntitiesProxyModelTest( QObject *parent = 0 )
      : ProxyModelTest( parent )
  {
  }

  protected:
    QVariantList getSignal(SignalType type, int start, int end)
    {
      return ProxyModelTest::getSignal(type, IndexFinder(), start, end);
    }

    void signalInsertion(const QString &name, int startRow, int rowsAffected)
    {
      ProxyModelTest::signalInsertion(name, IndexFinder(), startRow, rowsAffected, m_rowCount);
      m_rowCount += rowsAffected;
    }

    void signalRemoval(const QString &name, int startRow, int rowsAffected)
    {
      ProxyModelTest::signalRemoval(name, IndexFinder(), startRow, rowsAffected, m_rowCount);
      m_rowCount -= rowsAffected;
    }

    PersistentIndexChange getChange(int start, int end, int difference, bool toInvalid = false)
    {
      return ProxyModelTest::getChange(IndexFinder(), start, end, difference, toInvalid);
    }

private slots:
  void initTestCase();

  // TODO: Split these into tests in ProxyModelTest and initTestCase
  void testInsertionChangeAndRemoval();
  void testSameParentUp();
  void testSameParentDown();
  void testDifferentParentUp();
  void testDifferentParentDown();
  void testDifferentParentSameLevel();
  void testInsertionWithDescendants();

private:
  DescendantEntitiesProxyModel *m_proxyModel;
  IndexFinder m_rootIdxFinder;
  int m_rowCount;
};

void DescendantEntitiesProxyModelTest::initTestCase()
{
  m_proxyModel = new DescendantEntitiesProxyModel(this);
  setProxyModel(m_proxyModel);

  QList<QVariantList> signalList;
  QVariantList expected;
  QList<PersistentIndexChange> persistentList;
  m_rowCount = 0;
  int startRow = 0;
  int rowsInserted = 1;

  signalInsertion("insert01", startRow, rowsInserted);

  startRow = 1;
  rowsInserted = 10;
  signalInsertion("insert02", startRow, rowsInserted);

  startRow = 0;
  signalInsertion("insert03", startRow, rowsInserted);

  startRow = 21;
  signalInsertion("insert04", startRow, rowsInserted);

  startRow = 11;
  signalInsertion("insert05", startRow, rowsInserted);

  startRow = 31;
  signalInsertion("insert06", startRow, rowsInserted);

  startRow = 21;
  signalInsertion("insert07", startRow, rowsInserted);

  int accumulatedChange = 0;
  startRow = 17;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;

  startRow = 23;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;

  startRow = 29;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;
  persistentList << getChange(17, 17, accumulatedChange);

  startRow = 48;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;
  persistentList << getChange(18, 18, accumulatedChange);

  startRow = 59;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;

  persistentList << getChange(19, m_rowCount - 1, accumulatedChange);

  setExpected("insert08", signalList, persistentList);
  signalList.clear();
  persistentList.clear();
  m_rowCount += accumulatedChange;

  startRow = 11;
  int rowsRemoved = 1;
  signalRemoval("remove01", startRow, rowsRemoved);

  startRow = 57;
  rowsRemoved = 11;
  signalRemoval("remove02", startRow, rowsRemoved);

  startRow = 47;
  rowsRemoved = 1;
  signalRemoval("remove03", startRow, rowsRemoved);

  startRow = 55;
  signalRemoval("remove04", startRow, rowsRemoved);

  startRow = 50;
  signalRemoval("remove05", startRow, rowsRemoved);

  startRow = 47;
  rowsRemoved = 7;
  signalRemoval("remove06", startRow, rowsRemoved);

  startRow = 15;
  rowsRemoved = 31;
  signalRemoval("remove07", startRow, rowsRemoved);

}

void DescendantEntitiesProxyModelTest::testInsertionChangeAndRemoval()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ModelDataChangeCommand *mch;
  mch = new ModelDataChangeCommand(model, this);
  mch->setStartRow(0);
  mch->setEndRow(4);
  mch->doCommand();

  // Item 0-0
  // Item 1-0
  // Item 2-0
  // Item 3-0
  // Item 4-0

  // Item 0-0
  // Item 2-0
  // Item 3-0
  // Item 1-0
  // Item 4-0
//   2, 3 -1
//   1 2

  // Item 0-0
  // Item 3-0
  // Item 1-0
  // Item 2-0
  // Item 4-0
// 3 -2
// 1,2 +1

  ModelRemoveCommand *rem;
  rem = new ModelRemoveCommand(model, this);
  rem->setStartRow(2);
  rem->setEndRow(2);
  rem->doCommand();

  // If we get this far, modeltest didn't assert.
  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testSameParentDown()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 1;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ModelMoveCommand *mmc;
  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(3);
  mmc->setEndRow(5);
  mmc->setDestRow(8);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testSameParentUp()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  ins = new ModelInsertCommand(model, this);
  ins->setAncestorRowNumbers(ancestorRows);
  ins->setStartRow(0);
  ins->setEndRow(9);
  ins->doCommand();

  ModelMoveCommand *mmc;

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(8);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(7);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(6);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(5);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(4);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testDifferentParentUp()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ancestorRows.clear();
  ancestorRows << 2;

  ModelMoveCommand *mmc;
  mmc = new ModelMoveCommand(model, this);
  mmc->setDestAncestors(ancestorRows);
  mmc->setStartRow(7);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testDifferentParentDown()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ancestorRows.clear();
  ancestorRows << 2;

  ModelMoveCommand *mmc;
  mmc = new ModelMoveCommand(model, this);
  mmc->setDestAncestors(ancestorRows);
  mmc->setStartRow(6);
  mmc->setEndRow(7);
  mmc->setDestRow(9);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testDifferentParentSameLevel()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ancestorRows.clear();
  ancestorRows << 2;

  ModelMoveCommand *mmc;

  mmc = new ModelMoveCommand(model, this);
  mmc->setDestAncestors(ancestorRows);
  mmc->setStartRow(6);
  mmc->setEndRow(7);
  mmc->setDestRow(6);
  mmc->doCommand();

  QVERIFY(true);

}

void DescendantEntitiesProxyModelTest::testInsertionWithDescendants()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  // First insert 4 items to the root.
  ModelInsertCommand *ins = new ModelInsertCommand(model, this);
  ins->setStartRow(0);
  ins->setEndRow(3);
  ins->doCommand();

  ModelInsertWithDescendantsCommand *insDesc = new ModelInsertWithDescendantsCommand(model, this);
  QList<QPair<int, int> > descs;
  QPair<int, int> pair;
  pair.first = 1;   // On the first row,
  pair.second = 4;  // insert 4 items.
  descs << pair;
  pair.first = 2;   // Make the 6th new item
  pair.second = 5;  // have 5 descendants itself.
  descs << pair;
  insDesc->setNumDescendants(descs);
  insDesc->doCommand();

  QVERIFY(true);
}

QTEST_KDEMAIN(DescendantEntitiesProxyModelTest, GUI)
#include "descendantentitiesproxymodeltest.moc"
<commit_msg>Remove the test for insertion of a subtree.<commit_after>/*
    Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>

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

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

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

#include <QtTest>
#include <QtCore>
#include <qtest_kde.h>
#include <qtestevent.h>

#include "dynamictreemodel.h"
#include "../modeltest.h"
#include "../descendantentitiesproxymodel.h"
#include "proxymodeltest.h"

// #include "fakemonitor.h"

#include <QTreeView>

#include <kdebug.h>

using namespace Akonadi;

class DescendantEntitiesProxyModelTest : public ProxyModelTest
{
  Q_OBJECT
public:
  DescendantEntitiesProxyModelTest( QObject *parent = 0 )
      : ProxyModelTest( parent )
  {
  }

  protected:
    QVariantList getSignal(SignalType type, int start, int end)
    {
      return ProxyModelTest::getSignal(type, IndexFinder(), start, end);
    }

    void signalInsertion(const QString &name, int startRow, int rowsAffected)
    {
      ProxyModelTest::signalInsertion(name, IndexFinder(), startRow, rowsAffected, m_rowCount);
      m_rowCount += rowsAffected;
    }

    void signalRemoval(const QString &name, int startRow, int rowsAffected)
    {
      ProxyModelTest::signalRemoval(name, IndexFinder(), startRow, rowsAffected, m_rowCount);
      m_rowCount -= rowsAffected;
    }

    PersistentIndexChange getChange(int start, int end, int difference, bool toInvalid = false)
    {
      return ProxyModelTest::getChange(IndexFinder(), start, end, difference, toInvalid);
    }

private slots:
  void initTestCase();

  // TODO: Split these into tests in ProxyModelTest and initTestCase
  void testInsertionChangeAndRemoval();
  void testSameParentUp();
  void testSameParentDown();
  void testDifferentParentUp();
  void testDifferentParentDown();
  void testDifferentParentSameLevel();

private:
  DescendantEntitiesProxyModel *m_proxyModel;
  IndexFinder m_rootIdxFinder;
  int m_rowCount;
};

void DescendantEntitiesProxyModelTest::initTestCase()
{
  m_proxyModel = new DescendantEntitiesProxyModel(this);
  setProxyModel(m_proxyModel);

  QList<QVariantList> signalList;
  QVariantList expected;
  QList<PersistentIndexChange> persistentList;
  m_rowCount = 0;
  int startRow = 0;
  int rowsInserted = 1;

  signalInsertion("insert01", startRow, rowsInserted);

  startRow = 1;
  rowsInserted = 10;
  signalInsertion("insert02", startRow, rowsInserted);

  startRow = 0;
  signalInsertion("insert03", startRow, rowsInserted);

  startRow = 21;
  signalInsertion("insert04", startRow, rowsInserted);

  startRow = 11;
  signalInsertion("insert05", startRow, rowsInserted);

  startRow = 31;
  signalInsertion("insert06", startRow, rowsInserted);

  startRow = 21;
  signalInsertion("insert07", startRow, rowsInserted);

  int accumulatedChange = 0;
  startRow = 17;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;

  startRow = 23;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;

  startRow = 29;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;
  persistentList << getChange(17, 17, accumulatedChange);

  startRow = 48;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;
  persistentList << getChange(18, 18, accumulatedChange);

  startRow = 59;
  signalList << getSignal(RowsAboutToBeInserted, startRow, startRow + rowsInserted - 1);
  signalList << getSignal(RowsInserted, startRow, startRow + rowsInserted - 1);
  accumulatedChange += 10;

  persistentList << getChange(19, m_rowCount - 1, accumulatedChange);

  setExpected("insert08", signalList, persistentList);
  signalList.clear();
  persistentList.clear();
  m_rowCount += accumulatedChange;

  startRow = 11;
  int rowsRemoved = 1;
  signalRemoval("remove01", startRow, rowsRemoved);

  startRow = 57;
  rowsRemoved = 11;
  signalRemoval("remove02", startRow, rowsRemoved);

  startRow = 47;
  rowsRemoved = 1;
  signalRemoval("remove03", startRow, rowsRemoved);

  startRow = 55;
  signalRemoval("remove04", startRow, rowsRemoved);

  startRow = 50;
  signalRemoval("remove05", startRow, rowsRemoved);

  startRow = 47;
  rowsRemoved = 7;
  signalRemoval("remove06", startRow, rowsRemoved);

  startRow = 15;
  rowsRemoved = 31;
  signalRemoval("remove07", startRow, rowsRemoved);

}

void DescendantEntitiesProxyModelTest::testInsertionChangeAndRemoval()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ModelDataChangeCommand *mch;
  mch = new ModelDataChangeCommand(model, this);
  mch->setStartRow(0);
  mch->setEndRow(4);
  mch->doCommand();

  // Item 0-0
  // Item 1-0
  // Item 2-0
  // Item 3-0
  // Item 4-0

  // Item 0-0
  // Item 2-0
  // Item 3-0
  // Item 1-0
  // Item 4-0
//   2, 3 -1
//   1 2

  // Item 0-0
  // Item 3-0
  // Item 1-0
  // Item 2-0
  // Item 4-0
// 3 -2
// 1,2 +1

  ModelRemoveCommand *rem;
  rem = new ModelRemoveCommand(model, this);
  rem->setStartRow(2);
  rem->setEndRow(2);
  rem->doCommand();

  // If we get this far, modeltest didn't assert.
  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testSameParentDown()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 1;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ModelMoveCommand *mmc;
  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(3);
  mmc->setEndRow(5);
  mmc->setDestRow(8);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testSameParentUp()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  ins = new ModelInsertCommand(model, this);
  ins->setAncestorRowNumbers(ancestorRows);
  ins->setStartRow(0);
  ins->setEndRow(9);
  ins->doCommand();

  ModelMoveCommand *mmc;

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(8);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(7);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(6);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(5);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  mmc = new ModelMoveCommand(model, this);
  mmc->setStartRow(4);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testDifferentParentUp()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ancestorRows.clear();
  ancestorRows << 2;

  ModelMoveCommand *mmc;
  mmc = new ModelMoveCommand(model, this);
  mmc->setDestAncestors(ancestorRows);
  mmc->setStartRow(7);
  mmc->setEndRow(8);
  mmc->setDestRow(1);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testDifferentParentDown()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ancestorRows.clear();
  ancestorRows << 2;

  ModelMoveCommand *mmc;
  mmc = new ModelMoveCommand(model, this);
  mmc->setDestAncestors(ancestorRows);
  mmc->setStartRow(6);
  mmc->setEndRow(7);
  mmc->setDestRow(9);
  mmc->doCommand();

  QVERIFY(true);
}

void DescendantEntitiesProxyModelTest::testDifferentParentSameLevel()
{
  DynamicTreeModel *model = new DynamicTreeModel(this);

  DescendantEntitiesProxyModel *proxy = new DescendantEntitiesProxyModel(this);
  proxy->setSourceModel(model);

  QList<int> ancestorRows;

  ModelInsertCommand *ins;
  int max_runs = 2;
  for (int i = 0; i < max_runs; i++)
  {
    ins = new ModelInsertCommand(model, this);
    ins->setAncestorRowNumbers(ancestorRows);
    ins->setStartRow(0);
    ins->setEndRow(9);
    ins->doCommand();
    ancestorRows << 2;
  }

  ancestorRows.clear();
  ancestorRows << 2;

  ModelMoveCommand *mmc;

  mmc = new ModelMoveCommand(model, this);
  mmc->setDestAncestors(ancestorRows);
  mmc->setStartRow(6);
  mmc->setEndRow(7);
  mmc->setDestRow(6);
  mmc->doCommand();

  QVERIFY(true);

}

QTEST_KDEMAIN(DescendantEntitiesProxyModelTest, GUI)
#include "descendantentitiesproxymodeltest.moc"
<|endoftext|>


<commit_before>#include "mainboard.h"
#include "ui_mainboard.h"
#include <QTextStream>
#include <QLabel>
#include <QString>

MainBoard::MainBoard(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainBoard)
{
    ui->setupUi(this);
    this->setFixedSize(1920, 1080);
    this->setStyleSheet("background-color: #85C2FF;");

    const int BOARD_ROWS = 8;
    const int BOARD_COLS = 8;
    const int squares_size = 100;
    const int squares_label_width = 12;
    const int squares_label_height = 20;
    const int x_axis[8] = {480, 580, 680, 780, 880, 980, 1080, 1180}; //pushing columns from left to right, starting at 480 pixels
    const int y_axis[8] = {50, 150, 250, 350, 450, 550, 650, 750}; //pushing rows from top to bottom, starting at 50 pixels
    const QString numb_label[8] ={"8", "7", "6", "5", "4", "3", "2", "1"};
    const QString letter_label[8] = {"A", "B", "C", "D", "E", "F", "G", "H"};

    QLabel* Sqares[BOARD_COLS][BOARD_ROWS];
    QLabel* square_numb_label[8];
    QLabel* square_letter_label[8];

    //initializing each QLabel
    for(int i = 0; i < 8; i++)
    {
        square_letter_label[i] = new QLabel(this);
        square_numb_label[i] = new QLabel(this);

        for(int j = 0; j < 8; j++)
        {
            Sqares[i][j] = new QLabel(this);
        }
    }
    //chess board
    for(int i = 0; i < 8; i++)
    {
        square_letter_label[i]->setText(letter_label[i]);
        square_letter_label[i]->setGeometry(x_axis[i] + 45, y_axis[7] + 100, squares_label_width, squares_label_height);

        square_numb_label[i]->setText(numb_label[i]);
        square_numb_label[i]->setGeometry(x_axis[0] - 25,y_axis[i] + 35, squares_label_width, squares_label_height);
        for(int j = 0; j < 8; j++)
        {
            Sqares[i][j]->setGeometry(x_axis[i],y_axis[j], squares_size,squares_size);

            if((i%2) == 0)
            {
                if((j % 2) == 0)
                {
                    Sqares[i][j]->setStyleSheet("background-color: white;");
                }
                else
                {
                    Sqares[i][j]->setStyleSheet("background-color: black;");
                }
            }
            else
            {
               if((j % 2) != 0)
               {
                    Sqares[i][j]->setStyleSheet("background-color: white ;");
               }
               else
               {
                    Sqares[i][j]->setStyleSheet("background-color: black;");
               }
            }
        }
    }

    /* tester to see position of QLabel
    Sqares[1][1]->setStyleSheet("background-color: red");
    */

}

MainBoard::~MainBoard()
{
    delete ui;
}
<commit_msg>Style<commit_after>#include "mainboard.h"
#include "ui_mainboard.h"
#include <QTextStream>
#include <QLabel>
#include <QString>

MainBoard::MainBoard(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainBoard)
{
    ui->setupUi(this);
    this->setFixedSize(1920, 1080);
    this->setStyleSheet("background-color: #D6EBFF;");

    const int BOARD_ROWS = 8;
    const int BOARD_COLS = 8;
    const int squares_size = 100;
    const int squares_label_width = 12;
    const int squares_label_height = 20;
    const int x_axis[8] = {480, 580, 680, 780, 880, 980, 1080, 1180}; //pushing columns from left to right, starting at 480 pixels
    const int y_axis[8] = {50, 150, 250, 350, 450, 550, 650, 750}; //pushing rows from top to bottom, starting at 50 pixels
    const QString numb_label[8] ={"8", "7", "6", "5", "4", "3", "2", "1"};
    const QString letter_label[8] = {"A", "B", "C", "D", "E", "F", "G", "H"};

    QLabel* Sqares[BOARD_COLS][BOARD_ROWS];
    QLabel* square_numb_label[8];
    QLabel* square_letter_label[8];

    //initializing each QLabel
    for(int i = 0; i < 8; i++)
    {
        square_letter_label[i] = new QLabel(this);
        square_numb_label[i] = new QLabel(this);

        for(int j = 0; j < 8; j++)
        {
            Sqares[i][j] = new QLabel(this);
        }
    }
    //chess board
    for(int i = 0; i < 8; i++)
    {
        square_letter_label[i]->setText(letter_label[i]);
        square_letter_label[i]->setGeometry(x_axis[i] + 45, y_axis[7] + 100, squares_label_width, squares_label_height);

        square_numb_label[i]->setText(numb_label[i]);
        square_numb_label[i]->setGeometry(x_axis[0] - 25,y_axis[i] + 35, squares_label_width, squares_label_height);
        for(int j = 0; j < 8; j++)
        {
            Sqares[i][j]->setGeometry(x_axis[i],y_axis[j], squares_size,squares_size);

            if((i%2) == 0)
            {
                if((j % 2) == 0)
                {
                    Sqares[i][j]->setStyleSheet("background-color: #EBF5FF;");
                }
                else
                {
                    Sqares[i][j]->setStyleSheet("background-color: #0A1F33;");
                }
            }
            else
            {
               if((j % 2) != 0)
               {
                    Sqares[i][j]->setStyleSheet("background-color: #EBF5FF ;");
               }
               else
               {
                    Sqares[i][j]->setStyleSheet("background-color: #0A1F33;");
               }
            }
        }
    }

    /* tester to see position of QLabel
    Sqares[1][1]->setStyleSheet("background-color: red");
    */

}

MainBoard::~MainBoard()
{
    delete ui;
}
<|endoftext|>


<commit_before>/**
  @file Unit test for #Mission::import_mission_items_from_QGC_plan().
  @author Shakthi Prashanth <shakthi.prashanth.m@intel.com>
*/

#include <gtest/gtest.h>
#include <atomic>
#include <atomic>
#include "mission.h"
#include "mavlink_include.h"
#include "global_include.h"
#include "log.h"

using namespace dronecore;

struct QGCMissionItem {
    MAV_CMD cmd;
    std::vector<double> params;
};

Mission::Result compose_mission_items(MAV_CMD cmd, std::vector<double> params,
                                      std::shared_ptr<MissionItem> &new_mission_item,
                                      Mission::mission_items_t &mission_items)
{
    Mission::Result result = Mission::Result::SUCCESS;

    // Choosen "Do-While(0)" loop for the convenience of using `break` statement.
    do {
        if (cmd == MAV_CMD_NAV_WAYPOINT ||
            cmd == MAV_CMD_NAV_TAKEOFF ||
            cmd == MAV_CMD_NAV_LAND) {
            if (new_mission_item->has_position_set()) {
                mission_items.push_back(new_mission_item);
                new_mission_item = std::make_shared<MissionItem>();
            }
            if (cmd == MAV_CMD_NAV_WAYPOINT) {
                auto is_fly_thru = !(int(params[0]) > 0);
                new_mission_item->set_fly_through(is_fly_thru);
            }
            auto lat = params[4], lon = params[5];
            new_mission_item->set_position(lat, lon);

            auto rel_alt = float(params[6]);
            new_mission_item->set_relative_altitude(rel_alt);

        } else if (cmd == MAV_CMD_DO_MOUNT_CONTROL) {
            auto pitch = float(params[0]), yaw = float(params[2]);
            new_mission_item->set_gimbal_pitch_and_yaw(pitch, yaw);

        } else if (cmd == MAV_CMD_NAV_LOITER_TIME) {
            auto loiter_time_s = float(params[0]);
            new_mission_item->set_loiter_time(loiter_time_s);

        } else if (cmd == MAV_CMD_IMAGE_START_CAPTURE) {
            auto photo_interval = int(params[1]),  photo_count = int(params[2]);

            if (photo_interval > 0 && photo_count == 0) {
                new_mission_item->set_camera_action(MissionItem::CameraAction::START_PHOTO_INTERVAL);
                new_mission_item->set_camera_photo_interval(photo_interval);
            } else if (photo_interval == 0 && photo_count == 1) {
                new_mission_item->set_camera_action(MissionItem::CameraAction::TAKE_PHOTO);
            } else {
                LogErr() << "Mission item START_CAPTURE params unsupported.";
                result = Mission::Result::UNSUPPORTED;
                break;
            }

        } else if (cmd == MAV_CMD_IMAGE_STOP_CAPTURE) {
            new_mission_item->set_camera_action(MissionItem::CameraAction::STOP_PHOTO_INTERVAL);

        } else if (cmd == MAV_CMD_VIDEO_START_CAPTURE) {
            new_mission_item->set_camera_action(MissionItem::CameraAction::START_VIDEO);

        } else if (cmd == MAV_CMD_VIDEO_STOP_CAPTURE) {
            new_mission_item->set_camera_action(MissionItem::CameraAction::STOP_VIDEO);

        } else if (cmd == MAV_CMD_DO_CHANGE_SPEED) {
            enum { AirSpeed, GroundSpeed };
            auto speed_type = int(params[0]);
            auto speed_m_s = float(params[1]);
            auto throttle = params[2];
            auto is_absolute = (params[3] == 0);

            if (speed_type == int(GroundSpeed) && throttle < 0 && is_absolute) {
                new_mission_item->set_speed(speed_m_s);
            } else {
                LogErr() << cmd << "Mission item DO_CHANGE_SPEED params unsupported";
                result = Mission::Result::UNSUPPORTED;
                break;
            }
        } else {
            LogWarn() << "UNSUPPORTED mission item command (" << cmd << ")";
        }
    } while (false); // Executed once per method invokation.

    return result;
}

static void compare(const std::shared_ptr<MissionItem> local,
                    const std::shared_ptr<MissionItem> imported);

TEST(QGCMissionImport, ValidateQGCMissonItems)
{
    // These mission items are meant to match those in
    // file:://example/fly_qgc_mission/qgroundcontrol_sample.plan
    QGCMissionItem items_test[] = {
        { MAV_CMD_NAV_TAKEOFF, { 0., 0., 0., 0., 47.39781011, 8.54553801, 15. } },
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39779921, 8.54546693, 15. } },
        { MAV_CMD_DO_MOUNT_CONTROL, { 25.0, 0., 50.0 } }, // Gimbal pitch & yaw in deg
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39773658, 8.54543743, 15. } },
        { MAV_CMD_IMAGE_START_CAPTURE, { 0., 0., 1., } }, // Take 1 photo
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39768937, 8.54548034, 15. } },
        { MAV_CMD_IMAGE_START_CAPTURE, { 0, 1., 0., } }, // Start image capture
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39768029, 8.54561177, 15. } },
        { MAV_CMD_DO_CHANGE_SPEED, { 1., 100., -1., 0 } },
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39779649, 8.54566005, 15. } },
        { MAV_CMD_NAV_LOITER_TIME, { 30. } }, // Loiter for 30 seconds
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39779468, 8.54561445, 15. } },
        { MAV_CMD_VIDEO_START_CAPTURE, {} }, // Start video capture
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39784279, 8.54553533, 15. } },
        { MAV_CMD_IMAGE_STOP_CAPTURE, {} }, // Stop image capture
        { MAV_CMD_VIDEO_STOP_CAPTURE, {} }, // Stop video capture
    };

    // Build mission items for comparison
    Mission::mission_items_t mission_items_local;
    auto new_mission_item = std::make_shared<MissionItem>();
    Mission::Result result = Mission::Result::SUCCESS;

    for (auto &qgc_it : items_test) {
        auto cmd = qgc_it.cmd;
        auto params = qgc_it.params;
        result = compose_mission_items(cmd, params, new_mission_item, mission_items_local);
        EXPECT_EQ(result, Mission::Result::SUCCESS);
    }
    mission_items_local.push_back(new_mission_item);

    // Import Mission items from QGC plan
    Mission::mission_items_t mission_items_imported;
    const std::string QGC_SAMPLE_PLAN = "example/fly_qgc_mission/qgroundcontrol_sample.plan";
    Mission::Result import_result = Mission::import_mission_items_from_QGC_plan(
                                        mission_items_imported, QGC_SAMPLE_PLAN);
    ASSERT_EQ(import_result, Mission::Result::SUCCESS);
    EXPECT_NE(mission_items_imported.size(), 0);

    // Compare local & parsed mission items
    ASSERT_EQ(mission_items_local.size(), mission_items_imported.size());
    for (unsigned i = 0; i < mission_items_imported.size(); ++i) {
        compare(mission_items_local.at(i), mission_items_imported.at(i));
    }
}

void compare(const std::shared_ptr<MissionItem> local,
             const std::shared_ptr<MissionItem> imported)
{
    if (local->get_camera_action() == MissionItem::CameraAction::NONE) {
        // Non-Camera commands
        if (std::isfinite(local->get_latitude_deg())) {
            EXPECT_NEAR(local->get_latitude_deg(), imported->get_latitude_deg(), 1e-6);
        }
        if (std::isfinite(local->get_longitude_deg())) {
            EXPECT_NEAR(local->get_longitude_deg(), imported->get_longitude_deg(), 1e-6);
        }
        if (std::isfinite(local->get_relative_altitude_m())) {
            EXPECT_FLOAT_EQ(local->get_relative_altitude_m(),
                            imported->get_relative_altitude_m());
        }

        EXPECT_EQ(local->get_fly_through(), imported->get_fly_through());
        if (std::isfinite(local->get_speed_m_s())) {
            EXPECT_FLOAT_EQ(local->get_speed_m_s(), imported->get_speed_m_s());
        }
    }

    EXPECT_EQ(local->get_camera_action(), imported->get_camera_action());

    if (local->get_camera_action() == MissionItem::CameraAction::START_PHOTO_INTERVAL &&
        // Camera commands
        std::isfinite(local->get_camera_photo_interval_s())) {

        EXPECT_DOUBLE_EQ(local->get_camera_photo_interval_s(),
                         imported->get_camera_photo_interval_s());
    }

    if (std::isfinite(local->get_loiter_time_s())) {
        EXPECT_FLOAT_EQ(local->get_loiter_time_s(),
                        imported->get_loiter_time_s());
    }
}
<commit_msg>Relocate Unit test compose() method to the end (QGC Mission import)<commit_after>/**
  @file Unit test for #Mission::import_mission_items_from_QGC_plan().
  @author Shakthi Prashanth <shakthi.prashanth.m@intel.com>
*/

#include <gtest/gtest.h>
#include <atomic>
#include <atomic>
#include "mission.h"
#include "mavlink_include.h"
#include "global_include.h"
#include "log.h"

using namespace dronecore;

struct QGCMissionItem {
    MAV_CMD cmd;
    std::vector<double> params;
};

Mission::Result compose_mission_items(MAV_CMD cmd, std::vector<double> params,
                                      std::shared_ptr<MissionItem> &new_mission_item,
                                      Mission::mission_items_t &mission_items);

static void compare(const std::shared_ptr<MissionItem> local,
                    const std::shared_ptr<MissionItem> imported);

TEST(QGCMissionImport, ValidateQGCMissonItems)
{
    // These mission items are meant to match those in
    // file:://example/fly_qgc_mission/qgroundcontrol_sample.plan
    QGCMissionItem items_test[] = {
        { MAV_CMD_NAV_TAKEOFF, { 0., 0., 0., 0., 47.39781011, 8.54553801, 15. } },
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39779921, 8.54546693, 15. } },
        { MAV_CMD_DO_MOUNT_CONTROL, { 25.0, 0., 50.0 } }, // Gimbal pitch & yaw in deg
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39773658, 8.54543743, 15. } },
        { MAV_CMD_IMAGE_START_CAPTURE, { 0., 0., 1., } }, // Take 1 photo
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39768937, 8.54548034, 15. } },
        { MAV_CMD_IMAGE_START_CAPTURE, { 0, 1., 0., } }, // Start image capture
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39768029, 8.54561177, 15. } },
        { MAV_CMD_DO_CHANGE_SPEED, { 1., 100., -1., 0 } },
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39779649, 8.54566005, 15. } },
        { MAV_CMD_NAV_LOITER_TIME, { 30. } }, // Loiter for 30 seconds
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39779468, 8.54561445, 15. } },
        { MAV_CMD_VIDEO_START_CAPTURE, {} }, // Start video capture
        { MAV_CMD_NAV_WAYPOINT, { 0., 0., 0., 0., 47.39784279, 8.54553533, 15. } },
        { MAV_CMD_IMAGE_STOP_CAPTURE, {} }, // Stop image capture
        { MAV_CMD_VIDEO_STOP_CAPTURE, {} }, // Stop video capture
    };

    // Build mission items for comparison
    Mission::mission_items_t mission_items_local;
    auto new_mission_item = std::make_shared<MissionItem>();
    Mission::Result result = Mission::Result::SUCCESS;

    for (auto &qgc_it : items_test) {
        auto cmd = qgc_it.cmd;
        auto params = qgc_it.params;
        result = compose_mission_items(cmd, params, new_mission_item, mission_items_local);
        EXPECT_EQ(result, Mission::Result::SUCCESS);
    }
    mission_items_local.push_back(new_mission_item);

    // Import Mission items from QGC plan
    Mission::mission_items_t mission_items_imported;
    const std::string QGC_SAMPLE_PLAN = "example/fly_qgc_mission/qgroundcontrol_sample.plan";
    Mission::Result import_result = Mission::import_mission_items_from_QGC_plan(
                                        mission_items_imported, QGC_SAMPLE_PLAN);
    ASSERT_EQ(import_result, Mission::Result::SUCCESS);
    EXPECT_NE(mission_items_imported.size(), 0);

    // Compare local & parsed mission items
    ASSERT_EQ(mission_items_local.size(), mission_items_imported.size());
    for (unsigned i = 0; i < mission_items_imported.size(); ++i) {
        compare(mission_items_local.at(i), mission_items_imported.at(i));
    }
}

Mission::Result compose_mission_items(MAV_CMD cmd, std::vector<double> params,
                                      std::shared_ptr<MissionItem> &new_mission_item,
                                      Mission::mission_items_t &mission_items)
{
    Mission::Result result = Mission::Result::SUCCESS;

    // Choosen "Do-While(0)" loop for the convenience of using `break` statement.
    do {
        if (cmd == MAV_CMD_NAV_WAYPOINT ||
            cmd == MAV_CMD_NAV_TAKEOFF ||
            cmd == MAV_CMD_NAV_LAND) {
            if (new_mission_item->has_position_set()) {
                mission_items.push_back(new_mission_item);
                new_mission_item = std::make_shared<MissionItem>();
            }
            if (cmd == MAV_CMD_NAV_WAYPOINT) {
                auto is_fly_thru = !(int(params[0]) > 0);
                new_mission_item->set_fly_through(is_fly_thru);
            }
            auto lat = params[4], lon = params[5];
            new_mission_item->set_position(lat, lon);

            auto rel_alt = float(params[6]);
            new_mission_item->set_relative_altitude(rel_alt);

        } else if (cmd == MAV_CMD_DO_MOUNT_CONTROL) {
            auto pitch = float(params[0]), yaw = float(params[2]);
            new_mission_item->set_gimbal_pitch_and_yaw(pitch, yaw);

        } else if (cmd == MAV_CMD_NAV_LOITER_TIME) {
            auto loiter_time_s = float(params[0]);
            new_mission_item->set_loiter_time(loiter_time_s);

        } else if (cmd == MAV_CMD_IMAGE_START_CAPTURE) {
            auto photo_interval = int(params[1]),  photo_count = int(params[2]);

            if (photo_interval > 0 && photo_count == 0) {
                new_mission_item->set_camera_action(MissionItem::CameraAction::START_PHOTO_INTERVAL);
                new_mission_item->set_camera_photo_interval(photo_interval);
            } else if (photo_interval == 0 && photo_count == 1) {
                new_mission_item->set_camera_action(MissionItem::CameraAction::TAKE_PHOTO);
            } else {
                LogErr() << "Mission item START_CAPTURE params unsupported.";
                result = Mission::Result::UNSUPPORTED;
                break;
            }

        } else if (cmd == MAV_CMD_IMAGE_STOP_CAPTURE) {
            new_mission_item->set_camera_action(MissionItem::CameraAction::STOP_PHOTO_INTERVAL);

        } else if (cmd == MAV_CMD_VIDEO_START_CAPTURE) {
            new_mission_item->set_camera_action(MissionItem::CameraAction::START_VIDEO);

        } else if (cmd == MAV_CMD_VIDEO_STOP_CAPTURE) {
            new_mission_item->set_camera_action(MissionItem::CameraAction::STOP_VIDEO);

        } else if (cmd == MAV_CMD_DO_CHANGE_SPEED) {
            enum { AirSpeed, GroundSpeed };
            auto speed_type = int(params[0]);
            auto speed_m_s = float(params[1]);
            auto throttle = params[2];
            auto is_absolute = (params[3] == 0);

            if (speed_type == int(GroundSpeed) && throttle < 0 && is_absolute) {
                new_mission_item->set_speed(speed_m_s);
            } else {
                LogErr() << cmd << "Mission item DO_CHANGE_SPEED params unsupported";
                result = Mission::Result::UNSUPPORTED;
                break;
            }
        } else {
            LogWarn() << "UNSUPPORTED mission item command (" << cmd << ")";
        }
    } while (false); // Executed once per method invokation.

    return result;
}

void compare(const std::shared_ptr<MissionItem> local,
             const std::shared_ptr<MissionItem> imported)
{
    if (local->get_camera_action() == MissionItem::CameraAction::NONE) {
        // Non-Camera commands
        if (std::isfinite(local->get_latitude_deg())) {
            EXPECT_NEAR(local->get_latitude_deg(), imported->get_latitude_deg(), 1e-6);
        }
        if (std::isfinite(local->get_longitude_deg())) {
            EXPECT_NEAR(local->get_longitude_deg(), imported->get_longitude_deg(), 1e-6);
        }
        if (std::isfinite(local->get_relative_altitude_m())) {
            EXPECT_FLOAT_EQ(local->get_relative_altitude_m(),
                            imported->get_relative_altitude_m());
        }

        EXPECT_EQ(local->get_fly_through(), imported->get_fly_through());
        if (std::isfinite(local->get_speed_m_s())) {
            EXPECT_FLOAT_EQ(local->get_speed_m_s(), imported->get_speed_m_s());
        }
    }

    EXPECT_EQ(local->get_camera_action(), imported->get_camera_action());

    if (local->get_camera_action() == MissionItem::CameraAction::START_PHOTO_INTERVAL &&
        // Camera commands
        std::isfinite(local->get_camera_photo_interval_s())) {

        EXPECT_DOUBLE_EQ(local->get_camera_photo_interval_s(),
                         imported->get_camera_photo_interval_s());
    }

    if (std::isfinite(local->get_loiter_time_s())) {
        EXPECT_FLOAT_EQ(local->get_loiter_time_s(),
                        imported->get_loiter_time_s());
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <string_view>

#include <boost/pool/pool.hpp>

#include <b1/session/bytes_fwd_decl.hpp>
#include <b1/session/key_value_fwd_decl.hpp>

namespace b1::session
{

// \brief An immutable type to represent a pointer and a length.
//
class bytes final
{
public:
    friend class key_value;

    template <typename T, typename allocator>
    friend auto make_bytes(const T* data, size_t length, allocator& a) -> bytes;

    template <typename allocator>
    friend auto make_bytes(const void* data, size_t length, allocator& a) -> bytes;

    template <typename T>
    friend auto make_bytes(const T* data, size_t length) -> bytes;

    friend auto make_kv(bytes key, bytes value) -> key_value;

    template <typename key, typename value, typename allocator>
    friend auto make_kv(const key* the_key, size_t key_length, const value* the_value, size_t value_length, allocator& a) -> key_value;

    template <typename key, typename value>
    friend auto make_kv(const key* the_key, size_t key_length, const value* the_value, size_t value_length) -> key_value;

    template <typename allocator>
    friend auto make_kv(const void* key, size_t key_length, const void* value, size_t value_length, allocator& a) -> key_value;

    friend auto make_kv(const void* key, size_t key_length, const void* value, size_t value_length) -> key_value;

public:
    bytes(const bytes& b);
    bytes(bytes&& b);
    ~bytes();

    auto operator=(const bytes& b) -> bytes&;
    auto operator=(bytes&& b) -> bytes&;

    auto data() const -> const void * const;
    auto length() const -> size_t;

    auto operator==(const bytes& other) const -> bool;
    auto operator!=(const bytes& other) const -> bool;

    static const bytes invalid;

private:
    bytes() = default;

private:
    // The encoded address of the memory allocator that instantiated the memory this instance points to.
    // \warning The memory allocator MUST stay in scope during the lifetime of this instance.
    size_t* m_memory_allocator_address{nullptr};
    // \brief A pointer to a counter to keep track of the number of bytes instances that point to the memory address.
    // \remark When the counter reaches 0, the last instance will free the memory by invoking the free method on the memory allocator.
    // \warning Assuming that this type will be accessed synchronously.
    size_t* m_use_count_address{nullptr};
    // The size of the memory pointed to by m_data, in bytes.
    size_t* m_length{nullptr};
    // A pointer to a chunk of memory.
    void* m_data{nullptr};
};

// \brief Creates a new bytes instance with the given pointer and length.
//
// \tparam T The type stored in the array.
// \tparam allocator The memory allocator type used to manage the bytes memory. This type mush implement the "memory allocator" concept.
// \param data A pointer to an array of items to store in a bytes instance.
// \param length The number of items in the array.
// \param a The memory allocator used to instantiate the memory used by the bytes instance.
template <typename T, typename allocator>
auto make_bytes(const T* data, size_t length, allocator& a) -> bytes
{
    return make_bytes(reinterpret_cast<const void*>(data), length * sizeof(T), a);
}

template <typename allocator>
auto make_bytes(const void* data, size_t length, allocator& a) -> bytes
{
    auto result = bytes{};

    auto chunk_length = 3 * sizeof(size_t) + length;
    auto* chunk = reinterpret_cast<char*>(a->malloc(chunk_length));

    result.m_memory_allocator_address = reinterpret_cast<size_t*>(chunk);
    result.m_use_count_address = result.m_memory_allocator_address + sizeof(size_t);
    result.m_length = result.m_use_count_address + sizeof(size_t);
    result.m_data = result.m_length + sizeof(size_t);

    *(result.m_memory_allocator_address) = reinterpret_cast<size_t>(&a->free_function());
    *(result.m_use_count_address) = 1;
    *(result.m_length) = length;
    memcpy(result.m_data, data, length);

    return result;
}

template <>
inline auto make_bytes(const void* data, size_t length) -> bytes
{
    auto result = bytes{};

    result.m_memory_allocator_address = nullptr;
    result.m_use_count_address = nullptr;
    *(result.m_length) = length;
    result.m_data = reinterpret_cast<void*>(const_cast<void*>(data));

    return result;
}

// \brief Creates a new bytes instance with the given pointer and length.
//
// The returns a bytes "view" instance, in that the resulting bytes instance does not manage
// the given memory.
//
// \tparam T The type stored in the array.
// \param data A pointer to an array of items to store in a bytes instance.
// \param length The number of items in the array.
// \warning The resulting bytes instance does NOT take ownership of the given data pointer.
// \warning The data pointer must remain in scope for the lifetime of the given bytes instance.
template <typename T>
auto make_bytes(const T* data, size_t length) -> bytes
{
    return make_bytes(reinterpret_cast<const void*>(data), length * sizeof(T));
}

inline const bytes bytes::invalid{};

inline bytes::bytes(const bytes& b)
: m_memory_allocator_address{b.m_memory_allocator_address},
  m_use_count_address{b.m_use_count_address},
  m_length{b.m_use_count_address},
  m_data{b.m_data}
{
    ++(*m_use_count_address);
}

inline bytes::bytes(bytes&& b)
: m_memory_allocator_address{std::move(b.m_memory_allocator_address)},
  m_use_count_address{std::move(b.m_use_count_address)},
  m_length{std::move(b.m_use_count_address)},
  m_data{std::move(b.m_data)}
{
    b.m_use_count_address = nullptr;
    b.m_length = nullptr;
    b.m_data = nullptr;
}

inline bytes::~bytes()
{
    if (!m_data || !m_length || !m_use_count_address)
    {
        return;
    }

    if (--(*m_use_count_address) != 0)
    {
        return;
    }

    // TODO:  bytes shouldn't need to know the memory allocator in use.  Need a generic interface to cast to.
    // The memory pool must remain in scope for the lifetime of this instance.
    auto* free_function = reinterpret_cast<free_function_type*>(*m_memory_allocator_address);
    (*free_function)(m_data, 3 * sizeof(size_t) + *m_length);
}

inline auto bytes::operator=(const bytes& b) -> bytes&
{
    if (this == &b)
    {
        return *this;
    }

    m_memory_allocator_address = b.m_memory_allocator_address;
    m_use_count_address = b.m_use_count_address;
    m_length = b.m_length;
    m_data = b.m_data;

    ++(*m_use_count_address);

    return *this;
}

inline auto bytes::operator=(bytes&& b) -> bytes&
{
    if (this == &b)
    {
        return *this;
    }

    m_memory_allocator_address = b.m_memory_allocator_address;
    m_use_count_address = b.m_use_count_address;
    m_length = b.m_length;
    m_data = b.m_data;

    b.m_memory_allocator_address = nullptr;
    b.m_use_count_address = nullptr;
    b.m_length = nullptr;
    b.m_data = nullptr;

    return *this;
}

inline auto bytes::data() const -> const void * const
{
    return m_data;
}

inline auto bytes::length() const -> size_t
{
    if (!m_length)
    {
        return 0;
    }

    return *m_length;
}

inline auto bytes::operator==(const bytes& other) const -> bool
{
    if (m_length && other.m_length && m_data && other.m_data)
    {
        if (*m_length != *other.m_length)
        {
            return false;
        }

        return memcmp(m_data, other.m_data, *m_length) == 0 ? true : false;
    }

    return false;
}

inline auto bytes::operator!=(const bytes& other) const -> bool
{
    return !(*this == other);
}

}

namespace std
{
template <>
class less<b1::session::bytes> final
{
public:
    constexpr auto operator()(const b1::session::bytes& lhs, const b1::session::bytes& rhs) const -> bool
    {
        // Shorter keys are "less than" longer keys
        if (lhs.length() < rhs.length())
        {
            return true;
        }

        if (lhs.length() > rhs.length())
        {
            return false;
        }

        if (lhs.data() == nullptr && rhs.data() == nullptr)
        {
            return true;
        }

        if (!lhs.data())
        {
            return true;
        }

        if (!rhs.data())
        {
            return true;
        }

        return memcmp(lhs.data(), rhs.data(), lhs.length()) < 0;
    };
};

template <>
class greater<b1::session::bytes> final
{
public:
    constexpr auto operator()(const b1::session::bytes& lhs, const b1::session::bytes& rhs) const -> bool
    {
        // Shorter keys are "less than" longer keys
        if (lhs.length() > rhs.length())
        {
            return true;
        }

        if (lhs.length() < rhs.length())
        {
            return false;
        }

        if (lhs.data() == nullptr && rhs.data() == nullptr)
        {
            return true;
        }

        if (!lhs.data())
        {
            return true;
        }

        if (!rhs.data())
        {
            return true;
        }

        return memcmp(lhs.data(), rhs.data(), lhs.length()) > 0;
    };
};

template <>
class hash<b1::session::bytes> final
{
public:
  auto operator()(const b1::session::bytes& b) const -> size_t
  {
    return std::hash<std::string_view>{}({reinterpret_cast<const char*>(b.data()), b.length()});
  }
};

template <>
class equal_to<b1::session::bytes> final
{
public:
    constexpr auto operator()(const b1::session::bytes& lhs, const b1::session::bytes& rhs) const -> bool
    {
        if (lhs.length() != rhs.length())
        {
            return false;
        }

        if (lhs.data() == nullptr && rhs.data() == nullptr)
        {
            return true;
        }

        if (!lhs.data() || !rhs.data())
        {
            return false;
        }

        return memcmp(lhs.data(), rhs.data(), lhs.length()) == 0;
    }
};
}
<commit_msg>Changed comparator to make shorter keys larger than longer keys lexigraphically.<commit_after>#pragma once

#include <string_view>

#include <boost/pool/pool.hpp>

#include <b1/session/bytes_fwd_decl.hpp>
#include <b1/session/key_value_fwd_decl.hpp>

namespace b1::session
{

// \brief An immutable type to represent a pointer and a length.
//
class bytes final
{
public:
    friend class key_value;

    template <typename T, typename allocator>
    friend auto make_bytes(const T* data, size_t length, allocator& a) -> bytes;

    template <typename allocator>
    friend auto make_bytes(const void* data, size_t length, allocator& a) -> bytes;

    template <typename T>
    friend auto make_bytes(const T* data, size_t length) -> bytes;

    friend auto make_kv(bytes key, bytes value) -> key_value;

    template <typename key, typename value, typename allocator>
    friend auto make_kv(const key* the_key, size_t key_length, const value* the_value, size_t value_length, allocator& a) -> key_value;

    template <typename key, typename value>
    friend auto make_kv(const key* the_key, size_t key_length, const value* the_value, size_t value_length) -> key_value;

    template <typename allocator>
    friend auto make_kv(const void* key, size_t key_length, const void* value, size_t value_length, allocator& a) -> key_value;

    friend auto make_kv(const void* key, size_t key_length, const void* value, size_t value_length) -> key_value;

public:
    bytes(const bytes& b);
    bytes(bytes&& b);
    ~bytes();

    auto operator=(const bytes& b) -> bytes&;
    auto operator=(bytes&& b) -> bytes&;

    auto data() const -> const void * const;
    auto length() const -> size_t;

    auto operator==(const bytes& other) const -> bool;
    auto operator!=(const bytes& other) const -> bool;

    static const bytes invalid;

private:
    bytes() = default;

private:
    // The encoded address of the memory allocator that instantiated the memory this instance points to.
    // \warning The memory allocator MUST stay in scope during the lifetime of this instance.
    size_t* m_memory_allocator_address{nullptr};
    // \brief A pointer to a counter to keep track of the number of bytes instances that point to the memory address.
    // \remark When the counter reaches 0, the last instance will free the memory by invoking the free method on the memory allocator.
    // \warning Assuming that this type will be accessed synchronously.
    size_t* m_use_count_address{nullptr};
    // The size of the memory pointed to by m_data, in bytes.
    size_t* m_length{nullptr};
    // A pointer to a chunk of memory.
    void* m_data{nullptr};
};

// \brief Creates a new bytes instance with the given pointer and length.
//
// \tparam T The type stored in the array.
// \tparam allocator The memory allocator type used to manage the bytes memory. This type mush implement the "memory allocator" concept.
// \param data A pointer to an array of items to store in a bytes instance.
// \param length The number of items in the array.
// \param a The memory allocator used to instantiate the memory used by the bytes instance.
template <typename T, typename allocator>
auto make_bytes(const T* data, size_t length, allocator& a) -> bytes
{
    return make_bytes(reinterpret_cast<const void*>(data), length * sizeof(T), a);
}

template <typename allocator>
auto make_bytes(const void* data, size_t length, allocator& a) -> bytes
{
    auto result = bytes{};

    auto chunk_length = 3 * sizeof(size_t) + length;
    auto* chunk = reinterpret_cast<char*>(a->malloc(chunk_length));

    result.m_memory_allocator_address = reinterpret_cast<size_t*>(chunk);
    result.m_use_count_address = result.m_memory_allocator_address + sizeof(size_t);
    result.m_length = result.m_use_count_address + sizeof(size_t);
    result.m_data = result.m_length + sizeof(size_t);

    *(result.m_memory_allocator_address) = reinterpret_cast<size_t>(&a->free_function());
    *(result.m_use_count_address) = 1;
    *(result.m_length) = length;
    memcpy(result.m_data, data, length);

    return result;
}

template <>
inline auto make_bytes(const void* data, size_t length) -> bytes
{
    auto result = bytes{};

    result.m_memory_allocator_address = nullptr;
    result.m_use_count_address = nullptr;
    *(result.m_length) = length;
    result.m_data = reinterpret_cast<void*>(const_cast<void*>(data));

    return result;
}

// \brief Creates a new bytes instance with the given pointer and length.
//
// The returns a bytes "view" instance, in that the resulting bytes instance does not manage
// the given memory.
//
// \tparam T The type stored in the array.
// \param data A pointer to an array of items to store in a bytes instance.
// \param length The number of items in the array.
// \warning The resulting bytes instance does NOT take ownership of the given data pointer.
// \warning The data pointer must remain in scope for the lifetime of the given bytes instance.
template <typename T>
auto make_bytes(const T* data, size_t length) -> bytes
{
    return make_bytes(reinterpret_cast<const void*>(data), length * sizeof(T));
}

inline const bytes bytes::invalid{};

inline bytes::bytes(const bytes& b)
: m_memory_allocator_address{b.m_memory_allocator_address},
  m_use_count_address{b.m_use_count_address},
  m_length{b.m_use_count_address},
  m_data{b.m_data}
{
    ++(*m_use_count_address);
}

inline bytes::bytes(bytes&& b)
: m_memory_allocator_address{std::move(b.m_memory_allocator_address)},
  m_use_count_address{std::move(b.m_use_count_address)},
  m_length{std::move(b.m_use_count_address)},
  m_data{std::move(b.m_data)}
{
    b.m_use_count_address = nullptr;
    b.m_length = nullptr;
    b.m_data = nullptr;
}

inline bytes::~bytes()
{
    if (!m_data || !m_length || !m_use_count_address)
    {
        return;
    }

    if (--(*m_use_count_address) != 0)
    {
        return;
    }

    // TODO:  bytes shouldn't need to know the memory allocator in use.  Need a generic interface to cast to.
    // The memory pool must remain in scope for the lifetime of this instance.
    auto* free_function = reinterpret_cast<free_function_type*>(*m_memory_allocator_address);
    (*free_function)(m_data, 3 * sizeof(size_t) + *m_length);
}

inline auto bytes::operator=(const bytes& b) -> bytes&
{
    if (this == &b)
    {
        return *this;
    }

    m_memory_allocator_address = b.m_memory_allocator_address;
    m_use_count_address = b.m_use_count_address;
    m_length = b.m_length;
    m_data = b.m_data;

    ++(*m_use_count_address);

    return *this;
}

inline auto bytes::operator=(bytes&& b) -> bytes&
{
    if (this == &b)
    {
        return *this;
    }

    m_memory_allocator_address = b.m_memory_allocator_address;
    m_use_count_address = b.m_use_count_address;
    m_length = b.m_length;
    m_data = b.m_data;

    b.m_memory_allocator_address = nullptr;
    b.m_use_count_address = nullptr;
    b.m_length = nullptr;
    b.m_data = nullptr;

    return *this;
}

inline auto bytes::data() const -> const void * const
{
    return m_data;
}

inline auto bytes::length() const -> size_t
{
    if (!m_length)
    {
        return 0;
    }

    return *m_length;
}

inline auto bytes::operator==(const bytes& other) const -> bool
{
    if (m_length && other.m_length && m_data && other.m_data)
    {
        if (*m_length != *other.m_length)
        {
            return false;
        }

        return memcmp(m_data, other.m_data, *m_length) == 0 ? true : false;
    }

    return false;
}

inline auto bytes::operator!=(const bytes& other) const -> bool
{
    return !(*this == other);
}

}

namespace std
{
template <>
class less<b1::session::bytes> final
{
public:
    constexpr auto operator()(const b1::session::bytes& lhs, const b1::session::bytes& rhs) const -> bool
    {

        // Shorter keys are "greater than" longer keys
        if (lhs.length() < rhs.length())
        {
            return false;
        }

        if (lhs.length() > rhs.length())
        {
            return true;
        }

        if (lhs.data() == nullptr && rhs.data() == nullptr)
        {
            return true;
        }

        if (!lhs.data())
        {
            return true;
        }

        if (!rhs.data())
        {
            return true;
        }

        return memcmp(lhs.data(), rhs.data(), lhs.length()) < 0;
    };
};

template <>
class greater<b1::session::bytes> final
{
public:
    constexpr auto operator()(const b1::session::bytes& lhs, const b1::session::bytes& rhs) const -> bool
    {
        // Shorter keys are "greater than" longer keys
        if (lhs.length() > rhs.length())
        {
            return false;
        }

        if (lhs.length() < rhs.length())
        {
            return true;
        }

        if (lhs.data() == nullptr && rhs.data() == nullptr)
        {
            return true;
        }

        if (!lhs.data())
        {
            return true;
        }

        if (!rhs.data())
        {
            return true;
        }

        return memcmp(lhs.data(), rhs.data(), lhs.length()) > 0;
    };
};

template <>
class hash<b1::session::bytes> final
{
public:
  auto operator()(const b1::session::bytes& b) const -> size_t
  {
    return std::hash<std::string_view>{}({reinterpret_cast<const char*>(b.data()), b.length()});
  }
};

template <>
class equal_to<b1::session::bytes> final
{
public:
    constexpr auto operator()(const b1::session::bytes& lhs, const b1::session::bytes& rhs) const -> bool
    {
        if (lhs.length() != rhs.length())
        {
            return false;
        }

        if (lhs.data() == nullptr && rhs.data() == nullptr)
        {
            return true;
        }

        if (!lhs.data() || !rhs.data())
        {
            return false;
        }

        return memcmp(lhs.data(), rhs.data(), lhs.length()) == 0;
    }
};
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkImageAnisotropicDiffusion2D.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include "vtkImageAnisotropicDiffusion2D.h"

//----------------------------------------------------------------------------
// Description:
// Construct an instance of vtkImageAnisotropicDiffusion2D fitler.
vtkImageAnisotropicDiffusion2D::vtkImageAnisotropicDiffusion2D()
{
  this->SetFilteredAxes(VTK_IMAGE_X_AXIS, VTK_IMAGE_Y_AXIS);

  this->HandleBoundaries = 1;
  this->SetNumberOfIterations(4);
  this->DiffusionThreshold = 5.0;
  this->DiffusionFactor = 1;
  this->EdgesOn();
  this->CornersOn();
  this->GradientMagnitudeThresholdOff();

  this->NumberOfExecutionAxes = 2;
}

//----------------------------------------------------------------------------
void
vtkImageAnisotropicDiffusion2D::PrintSelf(ostream& os, vtkIndent indent)
{
  this->vtkImageSpatialFilter::PrintSelf(os, indent);
  os << indent << "NumberOfIterations: " << this->NumberOfIterations << "\n";
  os << indent << "DiffusionThreshold: " << this->DiffusionThreshold << "\n";
  os << indent << "DiffusionFactor: " << this->DiffusionFactor << "\n";

  if (this->Edges)
    {
    os << indent << "Edges: On\n";
    }
  else
    {
    os << indent << "Edges: Off\n";
    }

  if (this->Corners)
    {
    os << indent << "Corners: On\n";
    }
  else
    {
    os << indent << "Corners: Off\n";
    }

  if (this->GradientMagnitudeThreshold)
    {
    os << indent << "GradientMagnitudeThreshold: On\n";
    }
  else
    {
    os << indent << "GradientMagnitudeThreshold: Off\n";
    }
}

//----------------------------------------------------------------------------
void vtkImageAnisotropicDiffusion2D::SetFilteredAxes(int a0, int a1)
{
  int axes[2];

  axes[0] = a0;
  axes[1] = a1;
  this->vtkImageFilter::SetFilteredAxes(2, axes);
}

//----------------------------------------------------------------------------
// Description:
// This method sets the number of inputs which also affects the
// input neighborhood needed to compute one output pixel.
void vtkImageAnisotropicDiffusion2D::SetNumberOfIterations(int num)
{
  int temp;

  this->Modified();
  vtkDebugMacro(<< "SetNumberOfIterations: " << num);
  temp = num*2 + 1;
  this->KernelSize[0] = temp;
  this->KernelSize[1] = temp;
  this->KernelMiddle[0] = num;
  this->KernelMiddle[1] = num;

  this->NumberOfIterations = num;
}

//----------------------------------------------------------------------------
// Description:
// This method contains a switch statement that calls the correct
// templated function for the input region type.  The input and output regions
// must have the same data type.
void vtkImageAnisotropicDiffusion2D::Execute(vtkImageRegion *inRegion,
					     vtkImageRegion *outRegion)
{
  int idx;
  int extent[4];
  float ar0, ar1;
  vtkImageRegion *in;
  vtkImageRegion *out;
  vtkImageRegion *temp;

  inRegion->GetSpacing(ar0, ar1);

  // make the temporary regions to iterate over.
  in = vtkImageRegion::New();
  out = vtkImageRegion::New();

  // might as well make these floats
  in->SetExtent(VTK_IMAGE_DIMENSIONS, inRegion->GetExtent());
  in->SetScalarType(VTK_FLOAT);
  in->CopyRegionData(inRegion);
  out->SetExtent(VTK_IMAGE_DIMENSIONS, inRegion->GetExtent());
  out->SetScalarType(VTK_FLOAT);
  out->AllocateScalars();

  // To compute extent of diffusion which will shrink.
  outRegion->GetExtent(2, extent);

  // Loop performing the diffusion
  // Note: region extent could get smaller as the diffusion progresses
  // (but never get smaller than output region).
  for (idx = this->NumberOfIterations - 1; idx >= 0; --idx)
    {
    this->Iterate(in, out, ar0, ar1, extent, idx);
    temp = in;
    in = out;
    out = temp;
    }

  // copy results into output.
  outRegion->CopyRegionData(in);
  in->Delete ();
  out->Delete ();
}

//----------------------------------------------------------------------------
// Description:
// This method performs one pass of the diffusion filter.
// The inRegion and outRegion are assumed to have data type float,
// and have the same extent.
void vtkImageAnisotropicDiffusion2D::Iterate(vtkImageRegion *inRegion,
					     vtkImageRegion *outRegion,
					     float ar0, float ar1,
					     int *coreExtent, int count)
{
  int idx0, idx1;
  int inInc0, inInc1;
  int outInc0, outInc1;
  int inMin0, inMax0, inMin1, inMax1;
  int min0, max0, min1, max1;
  float *inPtr0, *inPtr1;
  float *outPtr0, *outPtr1;
  float th0, th1, th01;
  float df0, df1, df01;
  float temp, sum;

  inRegion->GetExtent(inMin0, inMax0, inMin1, inMax1);
  inRegion->GetIncrements(inInc0, inInc1);
  outRegion->GetIncrements(outInc0, outInc1);

  // Avoid warnings.
  th0 = th1 = th01 = df0 = df1 = df01 = 0.0;

  // Compute direction specific diffusion thresholds and factors.
  sum = 0.0;
  if (this->Edges)
    {
    th0 = ar0 * this->DiffusionThreshold;
    df0 = 1.0 / ar0;
    th1 = ar1 * this->DiffusionThreshold;
    df1 = 1.0 / ar1;
    // two edges per direction.
    sum += 2.0 * (df0 + df1);
    }
  if (this->Corners)
    {
    temp = sqrt(ar0*ar0 + ar1*ar1);
    th01 = temp * this->DiffusionThreshold;
    df01 = 1 / temp;
    // four corners per plane
    sum += 4 * (df01);
    }

  if (sum > 0.0)
    {
    temp = this->DiffusionFactor / sum;
    df0 *= temp;
    df1 *= temp;
    df01 *= temp;
    }
  else
    {
    vtkWarningMacro(<< "Iterate: NO NEIGHBORS");
    return;
    }

  // Compute the shrinking extent to loop over.
  min0 = coreExtent[0] - count;
  max0 = coreExtent[1] + count;
  min1 = coreExtent[2] - count;
  max1 = coreExtent[3] + count;
  // intersection
  min0 = (min0 > inMin0) ? min0 : inMin0;
  max0 = (max0 < inMax0) ? max0 : inMax0;
  min1 = (min1 > inMin1) ? min1 : inMin1;
  max1 = (max1 < inMax1) ? max1 : inMax1;

  vtkDebugMacro(<< "Iteration count: " << count << " ("
  << min0 << ", " << max0 << ", " << min1 << ", " << max1 << ")");

  // I apologize for explicitely diffusing each neighbor, but it is the easiest
  // way to deal with the boundary conditions.  Besides it is fast.
  // (Are you sure every one is correct?!!!)
  inPtr1 = (float *)(inRegion->GetScalarPointer(min0, min1));
  outPtr1 = (float *)(outRegion->GetScalarPointer(min0, min1));
  for (idx1 = min1; idx1 <= max1; ++idx1, inPtr1+=inInc1, outPtr1+=outInc1)
    {
    inPtr0 = inPtr1;
    outPtr0 = outPtr1;
    for (idx0 = min0; idx0 <= max0; ++idx0, inPtr0+=inInc0, outPtr0+=outInc0)
      {
      // Copy center
      *outPtr0 = *inPtr0;

      // Special case for gradient magnitude threhsold
      if (this->GradientMagnitudeThreshold)
	{
	float d0, d1;
	// compute the gradient magnitude (central differences).
	d0  = (idx0 != inMax0) ? inPtr0[inInc0] : *inPtr0;
	d0 -= (idx0 != inMin0) ? inPtr0[-inInc0] : *inPtr0;
	d0 /= ar0;
	d1  = (idx1 != inMax1) ? inPtr0[inInc1] : *inPtr0;
	d1 -= (idx1 != inMin1) ? inPtr0[-inInc1] : *inPtr0;
	d1 /= ar1;
	// If magnitude is big, don't diffuse.
	d0 = sqrt(d0*d0 + d1*d1);
	if (d0 > this->DiffusionThreshold)
	  {
	  // hack to not diffuse
	  th0 = th1 = th01 = 0.0;
	  }
	else
	  {
	  // hack to diffuse
	  th0 = th1 = th01 = VTK_LARGE_FLOAT;
	  }
	}

      // Start diffusing
      if (this->Edges)
	{
	// left
	if (idx0 != inMin0)
	  {
	  temp = inPtr0[-inInc0] - *inPtr0;
	  if (fabs(temp) < th0)
	    {
	    *outPtr0 += temp * df0;
	    }
	  }
	// right
	if (idx0 != inMax0)
	  {
	  temp = inPtr0[inInc0] - *inPtr0;
	  if (fabs(temp) < th0)
	    {
	    *outPtr0 += temp * df0;
	    }
	  }
	// up
	if (idx1 != inMin1)
	  {
	  temp = inPtr0[-inInc1] - *inPtr0;
	  if (fabs(temp) < th1)
	    {
	    *outPtr0 += temp * df1;
	    }
	  }
	// down
	if (idx1 != inMax1)
	  {
	  temp = inPtr0[inInc1] - *inPtr0;
	  if (fabs(temp) < th1)
	    {
	    *outPtr0 += temp * df1;
	    }
	  }
	}

      if (this->Corners)
	{
	// left up
	if (idx0 != inMin0 && idx1 != inMin1)
	  {
	  temp = inPtr0[-inInc0-inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	    {
	    *outPtr0 += temp * df01;
	    }
	  }
	// right up
	if (idx0 != inMax0 && idx1 != inMin1)
	  {
	  temp = inPtr0[inInc0-inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	    {
	    *outPtr0 += temp * df01;
	    }
	  }
	// left down
	if (idx0 != inMin0 && idx1 != inMax1)
	  {
	  temp = inPtr0[-inInc0+inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	      {
	      *outPtr0 += temp * df01;
	      }
	  }
	// right down
	if (idx0 != inMax0 && idx1 != inMax1)
	  {
	  temp = inPtr0[inInc0+inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	    {
	    *outPtr0 += temp * df01;
	    }
	  }
	}
      }
    }
}

<commit_msg>ERR: added GetScalarPointer<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageAnisotropicDiffusion2D.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include "vtkImageAnisotropicDiffusion2D.h"

//----------------------------------------------------------------------------
// Description:
// Construct an instance of vtkImageAnisotropicDiffusion2D fitler.
vtkImageAnisotropicDiffusion2D::vtkImageAnisotropicDiffusion2D()
{
  this->SetFilteredAxes(VTK_IMAGE_X_AXIS, VTK_IMAGE_Y_AXIS);

  this->HandleBoundaries = 1;
  this->SetNumberOfIterations(4);
  this->DiffusionThreshold = 5.0;
  this->DiffusionFactor = 1;
  this->EdgesOn();
  this->CornersOn();
  this->GradientMagnitudeThresholdOff();

  this->NumberOfExecutionAxes = 2;
}

//----------------------------------------------------------------------------
void
vtkImageAnisotropicDiffusion2D::PrintSelf(ostream& os, vtkIndent indent)
{
  this->vtkImageSpatialFilter::PrintSelf(os, indent);
  os << indent << "NumberOfIterations: " << this->NumberOfIterations << "\n";
  os << indent << "DiffusionThreshold: " << this->DiffusionThreshold << "\n";
  os << indent << "DiffusionFactor: " << this->DiffusionFactor << "\n";

  if (this->Edges)
    {
    os << indent << "Edges: On\n";
    }
  else
    {
    os << indent << "Edges: Off\n";
    }

  if (this->Corners)
    {
    os << indent << "Corners: On\n";
    }
  else
    {
    os << indent << "Corners: Off\n";
    }

  if (this->GradientMagnitudeThreshold)
    {
    os << indent << "GradientMagnitudeThreshold: On\n";
    }
  else
    {
    os << indent << "GradientMagnitudeThreshold: Off\n";
    }
}

//----------------------------------------------------------------------------
void vtkImageAnisotropicDiffusion2D::SetFilteredAxes(int a0, int a1)
{
  int axes[2];

  axes[0] = a0;
  axes[1] = a1;
  this->vtkImageFilter::SetFilteredAxes(2, axes);
}

//----------------------------------------------------------------------------
// Description:
// This method sets the number of inputs which also affects the
// input neighborhood needed to compute one output pixel.
void vtkImageAnisotropicDiffusion2D::SetNumberOfIterations(int num)
{
  int temp;

  this->Modified();
  vtkDebugMacro(<< "SetNumberOfIterations: " << num);
  temp = num*2 + 1;
  this->KernelSize[0] = temp;
  this->KernelSize[1] = temp;
  this->KernelMiddle[0] = num;
  this->KernelMiddle[1] = num;

  this->NumberOfIterations = num;
}

//----------------------------------------------------------------------------
// Description:
// This method contains a switch statement that calls the correct
// templated function for the input region type.  The input and output regions
// must have the same data type.
void vtkImageAnisotropicDiffusion2D::Execute(vtkImageRegion *inRegion,
					     vtkImageRegion *outRegion)
{
  int idx;
  int extent[4];
  float ar0, ar1;
  vtkImageRegion *in;
  vtkImageRegion *out;
  vtkImageRegion *temp;

  inRegion->GetSpacing(ar0, ar1);

  // make the temporary regions to iterate over.
  in = vtkImageRegion::New();
  out = vtkImageRegion::New();

  // might as well make these floats
  in->SetExtent(VTK_IMAGE_DIMENSIONS, inRegion->GetExtent());
  in->SetScalarType(VTK_FLOAT);
  in->CopyRegionData(inRegion);
  out->SetExtent(VTK_IMAGE_DIMENSIONS, inRegion->GetExtent());
  out->SetScalarType(VTK_FLOAT);
  out->AllocateScalars();

  // To compute extent of diffusion which will shrink.
  outRegion->GetExtent(2, extent);

  // Loop performing the diffusion
  // Note: region extent could get smaller as the diffusion progresses
  // (but never get smaller than output region).
  for (idx = this->NumberOfIterations - 1; idx >= 0; --idx)
    {
    this->Iterate(in, out, ar0, ar1, extent, idx);
    temp = in;
    in = out;
    out = temp;
    }

  // copy results into output.

  // NOTE: This method will allocate the data.
  // ImageRegion::SetExtent should not be modifying the Data's extent
  //
  outRegion->GetScalarPointer ();
  outRegion->CopyRegionData(in);

  in->Delete ();
  out->Delete ();
}

//----------------------------------------------------------------------------
// Description:
// This method performs one pass of the diffusion filter.
// The inRegion and outRegion are assumed to have data type float,
// and have the same extent.
void vtkImageAnisotropicDiffusion2D::Iterate(vtkImageRegion *inRegion,
					     vtkImageRegion *outRegion,
					     float ar0, float ar1,
					     int *coreExtent, int count)
{
  int idx0, idx1;
  int inInc0, inInc1;
  int outInc0, outInc1;
  int inMin0, inMax0, inMin1, inMax1;
  int min0, max0, min1, max1;
  float *inPtr0, *inPtr1;
  float *outPtr0, *outPtr1;
  float th0, th1, th01;
  float df0, df1, df01;
  float temp, sum;

  inRegion->GetExtent(inMin0, inMax0, inMin1, inMax1);
  inRegion->GetIncrements(inInc0, inInc1);
  outRegion->GetIncrements(outInc0, outInc1);

  // Avoid warnings.
  th0 = th1 = th01 = df0 = df1 = df01 = 0.0;

  // Compute direction specific diffusion thresholds and factors.
  sum = 0.0;
  if (this->Edges)
    {
    th0 = ar0 * this->DiffusionThreshold;
    df0 = 1.0 / ar0;
    th1 = ar1 * this->DiffusionThreshold;
    df1 = 1.0 / ar1;
    // two edges per direction.
    sum += 2.0 * (df0 + df1);
    }
  if (this->Corners)
    {
    temp = sqrt(ar0*ar0 + ar1*ar1);
    th01 = temp * this->DiffusionThreshold;
    df01 = 1 / temp;
    // four corners per plane
    sum += 4 * (df01);
    }

  if (sum > 0.0)
    {
    temp = this->DiffusionFactor / sum;
    df0 *= temp;
    df1 *= temp;
    df01 *= temp;
    }
  else
    {
    vtkWarningMacro(<< "Iterate: NO NEIGHBORS");
    return;
    }

  // Compute the shrinking extent to loop over.
  min0 = coreExtent[0] - count;
  max0 = coreExtent[1] + count;
  min1 = coreExtent[2] - count;
  max1 = coreExtent[3] + count;
  // intersection
  min0 = (min0 > inMin0) ? min0 : inMin0;
  max0 = (max0 < inMax0) ? max0 : inMax0;
  min1 = (min1 > inMin1) ? min1 : inMin1;
  max1 = (max1 < inMax1) ? max1 : inMax1;

  vtkDebugMacro(<< "Iteration count: " << count << " ("
  << min0 << ", " << max0 << ", " << min1 << ", " << max1 << ")");

  // I apologize for explicitely diffusing each neighbor, but it is the easiest
  // way to deal with the boundary conditions.  Besides it is fast.
  // (Are you sure every one is correct?!!!)
  inPtr1 = (float *)(inRegion->GetScalarPointer(min0, min1));
  outPtr1 = (float *)(outRegion->GetScalarPointer(min0, min1));
  for (idx1 = min1; idx1 <= max1; ++idx1, inPtr1+=inInc1, outPtr1+=outInc1)
    {
    inPtr0 = inPtr1;
    outPtr0 = outPtr1;
    for (idx0 = min0; idx0 <= max0; ++idx0, inPtr0+=inInc0, outPtr0+=outInc0)
      {
      // Copy center
      *outPtr0 = *inPtr0;

      // Special case for gradient magnitude threhsold
      if (this->GradientMagnitudeThreshold)
	{
	float d0, d1;
	// compute the gradient magnitude (central differences).
	d0  = (idx0 != inMax0) ? inPtr0[inInc0] : *inPtr0;
	d0 -= (idx0 != inMin0) ? inPtr0[-inInc0] : *inPtr0;
	d0 /= ar0;
	d1  = (idx1 != inMax1) ? inPtr0[inInc1] : *inPtr0;
	d1 -= (idx1 != inMin1) ? inPtr0[-inInc1] : *inPtr0;
	d1 /= ar1;
	// If magnitude is big, don't diffuse.
	d0 = sqrt(d0*d0 + d1*d1);
	if (d0 > this->DiffusionThreshold)
	  {
	  // hack to not diffuse
	  th0 = th1 = th01 = 0.0;
	  }
	else
	  {
	  // hack to diffuse
	  th0 = th1 = th01 = VTK_LARGE_FLOAT;
	  }
	}

      // Start diffusing
      if (this->Edges)
	{
	// left
	if (idx0 != inMin0)
	  {
	  temp = inPtr0[-inInc0] - *inPtr0;
	  if (fabs(temp) < th0)
	    {
	    *outPtr0 += temp * df0;
	    }
	  }
	// right
	if (idx0 != inMax0)
	  {
	  temp = inPtr0[inInc0] - *inPtr0;
	  if (fabs(temp) < th0)
	    {
	    *outPtr0 += temp * df0;
	    }
	  }
	// up
	if (idx1 != inMin1)
	  {
	  temp = inPtr0[-inInc1] - *inPtr0;
	  if (fabs(temp) < th1)
	    {
	    *outPtr0 += temp * df1;
	    }
	  }
	// down
	if (idx1 != inMax1)
	  {
	  temp = inPtr0[inInc1] - *inPtr0;
	  if (fabs(temp) < th1)
	    {
	    *outPtr0 += temp * df1;
	    }
	  }
	}

      if (this->Corners)
	{
	// left up
	if (idx0 != inMin0 && idx1 != inMin1)
	  {
	  temp = inPtr0[-inInc0-inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	    {
	    *outPtr0 += temp * df01;
	    }
	  }
	// right up
	if (idx0 != inMax0 && idx1 != inMin1)
	  {
	  temp = inPtr0[inInc0-inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	    {
	    *outPtr0 += temp * df01;
	    }
	  }
	// left down
	if (idx0 != inMin0 && idx1 != inMax1)
	  {
	  temp = inPtr0[-inInc0+inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	      {
	      *outPtr0 += temp * df01;
	      }
	  }
	// right down
	if (idx0 != inMax0 && idx1 != inMax1)
	  {
	  temp = inPtr0[inInc0+inInc1] - *inPtr0;
	  if (fabs(temp) < th01)
	    {
	    *outPtr0 += temp * df01;
	    }
	  }
	}
      }
    }
}

<|endoftext|>