...
  View open merge request
Commits (8)
......@@ -2,6 +2,8 @@ project(Patate)
cmake_minimum_required(VERSION 2.8.10)
set(PATATE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
# guard against in-source builds (source: Eigen)
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
......@@ -34,9 +36,10 @@ endif()
# Add core code source, so it is visible in dev environements #
################################################################################
add_subdirectory(Patate/Grenaille EXCLUDE_FROM_ALL)
add_subdirectory(Patate/Vitelotte EXCLUDE_FROM_ALL)
add_subdirectory(Patate/common)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Patate/Grenaille EXCLUDE_FROM_ALL)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Patate/Vitelotte EXCLUDE_FROM_ALL)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Patate/common)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Patate/Shelves EXCLUDE_FROM_ALL)
################################################################################
......
project(Shelves)
cmake_minimum_required(VERSION 2.8)
FILE ( GLOB SHELVES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
)
FILE ( GLOB SHELVES_IMPL
${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp
)
message("ROTO : ${PATATE_ROOT}")
add_library (Shelves OBJECT ${SHELVES_HEADERS} ${SHELVES_IMPL})
set_target_properties(Shelves PROPERTIES LINKER_LANGUAGE C++)
target_include_directories(Shelves PUBLIC
$<BUILD_INTERFACE:${PATATE_ROOT}>
$<INSTALL_INTERFACE:include> # <prefix>/include/mylib
)
/*!
\brief General-purpose and experimental functionalities are put on the Shelves.
This module aims at providing simple-to-use utility classes, offering
efficient algorithms and data-structures to be used conjointly with
the main patates (e.g. Grenaille, Vitelotte).
Shelves is not like standard Patate modules: it is a place where we
put our new experimental features, our super-efficient datastructures
and our conditionner bottles.
As a result, Shelves has no general Concepts to rely on, you need to
browse each classe documentation for a dedicated overview.
Right now, Shelves includes:
- AABBox: An Axis-Aligned Bounding Box, with Dimension and Scalar template parameters
- KdTree: A generic implementation for point-based KdTree, tailored for proximity
and kd-queries. Uses AABBox.
*/
namespace Shelves
{
} // End namespace Grenaille
namespace Shelves
{
/*!
\page shelves_user_manual_page User Manual
\authors Nicolas Mellado, Moos Hueting, Gael Guennebaud
\section shelves_user_manual_intro Overview
This module aims at providing simple-to-use utility classes, offering
efficient algorithms and data-structures to be used conjointly with
the main patates (e.g. Grenaille, Vitelotte).
Shelves is not like standard Patate modules: it is a place where we
put our new experimental features, our super-efficient datastructures
and our conditionner bottles.
As a result, Shelves has no general Concepts to rely on, you need to
browse each classe documentation for a dedicated overview.
Right now, Shelves includes:
- AABBox: An Axis-Aligned Bounding Box, with Dimension and Scalar template parameters
- KdTree: A generic implementation for point-based KdTree, tailored for proximity
and kd-queries. Uses AABBox.
\image html shelves.svg
*/
}
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
\authors Gael Guennebaud, Nicolas Mellado
*/
#ifndef _SHELVES_BOUNDEDHEAPPRIORITYQUEUE_
#define _SHELVES_BOUNDEDHEAPPRIORITYQUEUE_
#include <algorithm>
namespace Shelves{
template <typename Index, typename Weight>
struct BoundedHeapPriorityElement
{
Weight weight;
Index index;
};
/*!
\brief Base class for bounded-size priority queue
Be carrefull that the resulting queue isn't sorted, but all the elements
that are present at the end of the insertion process are all the
smallest/greatest of the set (ie. the SIZE smallest elements in the following
code).
\snippet Shelves/boundedHeapPriorityQueue.cpp Using BoundedHeapMinPriorityQueue
*/
template <typename Index,
typename Weight,
typename Comp > class BoundedHeapPriorityQueueBase
{
public:
using Element = BoundedHeapPriorityElement<Index, Weight>;
BoundedHeapPriorityQueueBase(void)
{
mElements = 0;
mMaxSize = 0;
mCount = 0;
}
inline void reserve(int maxSize)
{
if (mMaxSize!=maxSize)
{
mMaxSize = maxSize;
delete[] mElements;
mElements = new Element[mMaxSize];
mpOffsetedElements = (mElements-1);
}
reset();
}
/*!
* \brief reset Reset the queue
* \warning Does not free memory
*/
inline void reset() { mCount = 0; }
inline bool isFull() const { return mCount == mMaxSize; }
/*!
* returns number of elements inserted in queue
*/
inline int size() const { return mCount; }
constexpr Element* begin() { return mElements; }
constexpr Element* end() { return mElements+mCount; }
inline void insert(Index index, Weight weight)
{
Element e;
e.index = index;
e.weight = weight;
insert(e);
}
inline void insert(Element e)
{
Comp comp;
if (mCount==mMaxSize)
{
if (comp (e, mElements[0]))
{
register int j, k;
j = 1;
k = 2;
while (k <= mMaxSize)
{
Element* z = &(mpOffsetedElements[k]);
if ((k < mMaxSize) && comp(*z, mpOffsetedElements[k+1]))
z = &(mpOffsetedElements[++k]);
if(! comp (e, *z))
break;
mpOffsetedElements[j] = *z;
j = k;
k = 2 * j;
}
mpOffsetedElements[j] = e;
}
}
else
{
int i, j;
i = ++mCount;
while (i >= 2)
{
j = i >> 1;
Element& y = mpOffsetedElements[j];
if( ! comp (y, e))
break;
mpOffsetedElements[i] = y;
i = j;
}
mpOffsetedElements[i] = e;
}
}
protected:
int mCount;
int mMaxSize;
Element* mElements;
Element* mpOffsetedElements;
}; // class HeapMaxPriorityQueue
template <typename Index, typename Weight>
struct BoundedHeapMaxPriorityComp {
using Element = BoundedHeapPriorityElement<Index, Weight>;
inline bool operator()(const Element& lhs, const Element& rhs) {
return lhs.weight > rhs.weight;
}
};
template <typename Index, typename Weight>
struct BoundedHeapMinPriorityComp {
using Element = BoundedHeapPriorityElement<Index, Weight>;
inline bool operator()(const Element& lhs, const Element& rhs) {
return lhs.weight < rhs.weight;
}
};
//! \brief Priority Queue storing the smallest elements
template <typename Index, typename Weight>
using BoundedHeapMinPriorityQueue = BoundedHeapPriorityQueueBase<Index, Weight, BoundedHeapMinPriorityComp<Index, Weight>>;
//! \brief Priority Queue storing the greatest elements
template <typename Index, typename Weight>
using BoundedHeapMaxPriorityQueue = BoundedHeapPriorityQueueBase<Index, Weight, BoundedHeapMaxPriorityComp<Index, Weight>>;
} // namespace Shelves
#endif
This diff is collapsed.
......@@ -51,4 +51,25 @@
<div class="clear"></div>
\section patate_overview_sec_shelves Shelves
\htmlonly
<div class="dessin"><img src="images/shelves.png" border="0px" width="180" height="200" alt=""/></div>
\endhtmlonly
<i> Nicolas Mellado, Moos Hueting, Gael Guennebaud </i>
This module provides single-files functionalities typically needed in Computer Graphics applications.
These functionalities does not fit a specific Patate module, so we put them on the Shelves for
further use.
When a set of related functionalities takes too much space on the Shelves, a new Patate is expected
to grown from them.
<div class="clear"></div>
<span style="padding-right: 20px;">\ref shelves_user_manual_page "User Manual"</span><span style="padding-right: 20px;">\ref shelves_example_page "Examples"</span><span style="padding-right: 20px;">\ref Shelves "References"</span>
<div class="clear"></div>
*/
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef _PATATE_SHELVES_
#define _PATATE_SHELVES_
// First inclue Eigen Core
#include <Eigen/Core>
// Include common stuff
#include "common/defines.h"
// not supported on cuda
#ifndef __CUDACC__
#include "Shelves/src/kdtree.h"
#include "Shelves/src/boundedHeapPriorityQueue.h"
#endif
// Include Shelves Algorithms
#endif //_PATATE_SHELVES_
......@@ -766,7 +766,8 @@ EXCLUDE_SYMBOLS =
# the \include command).
EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/examples \
@CMAKE_CURRENT_BINARY_DIR@/doc-src
@CMAKE_CURRENT_BINARY_DIR@/doc-src \
@CMAKE_CURRENT_SOURCE_DIR@/tests
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
......
This diff is collapsed.
......@@ -55,6 +55,11 @@
<tab type="user" visible="yes" url="@ref vitelotte_example_gen_mesh_page" title="MVG from SVG"/>
</tab>
</tab>
<tab type="usergroup" url="shelves_user_manual_page.html" title="Shelves">
<tab type="usergroup" url="shelves_user_manual_page.html" title="User Manual">
<tab type="user" visible="yes" url="shelves_user_manual_kdtree_page.html" title="KdTree"/>
</tab>
</tab>
</tab>
<tab type="pages" visible="no" title="" intro=""/>
<tab type="modules" visible="no" title="" intro=""/>
......
......@@ -7,7 +7,7 @@ include_directories(${CMAKE_SOURCE_DIR})
# Generate split test header file only if it does not yet exist
# in order to prevent a rebuild everytime cmake is configured.
if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h)
if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h "")
foreach(i RANGE 1 999)
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h
......@@ -65,7 +65,7 @@ macro(add_multi_test filename)
string(REGEX MATCHALL "(.*)\\.c.*" dummy "${filename}")
set(testname ${CMAKE_MATCH_1})
file(READ "${filename}" test_source)
set(parts 0)
string(REGEX MATCHALL "CALL_SUBTEST_[0-9]+|TEST_PART_[0-9]+|PATATE_SUFFIXES(;[0-9]+)+" occurences "${test_source}")
......@@ -89,5 +89,6 @@ endmacro(add_multi_test)
add_subdirectory(Grenaille)
add_subdirectory(Vitelotte)
add_subdirectory(Shelves)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
################################################################################
# Grenaille #
################################################################################
add_multi_test(kdtree.cpp)
add_multi_test(boundedHeapPriorityQueue.cpp)
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*!
\file tests/Shelves/boundedHeapPriorityQueue.cpp
\brief Test Priority Queue utility functions
*/
#include "../common/testing.h"
#include "../common/testUtils.h"
#include "Patate/shelves.h"
#include <vector>
#include <algorithm>
#include <chrono> // std::chrono::seconds, std::chrono::milliseconds
// std::chrono::duration_cast
using namespace std;
using namespace Grenaille;
template<typename Scalar, int size>
void testFunction()
{
//! [Using BoundedHeapMinPriorityQueue]
using namespace Shelves;
BoundedHeapMinPriorityQueue <int, float> q;
q.reserve( size );
int invId = 0xffffffff;
q.insert(invId, std::numeric_limits<float>::max());
for (unsigned int j = 0; j != 2*size; j++){
float tmp = rand() % 10 + 1;
cout << "insert " << tmp << " in position " << j << std::endl;
q.insert( j, tmp );
}
for(auto e : q)
cout << e.index << " : " << e.weight << std::endl;;
// Check the max element is not in the queue anymore
auto it = std::find_if( q.begin(), q.end(), [invId](auto el) { return el.index == invId;} );
VERIFY(it == q.end());
//! [Using BoundedHeapMinPriorityQueue]
}
template<typename Scalar>
void callSubTests()
{
for(int i = 0; i < 1; ++i)
{
CALL_SUBTEST(( testFunction<Scalar, 10>() ));
}
}
int main(int argc, char** argv)
{
if(!init_testing(argc, argv))
{
return EXIT_FAILURE;
}
cout << "Test Kdtree functions" << endl;
callSubTests<float>();
//callSubTests<double>();
//callSubTests<long double>();
cout << "Ok..." << endl;
}
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*!
\file test/Shelves/kdtree.cpp
\brief Test kdtree utility functions
*/
#include "../common/testing.h"
#include "../common/testUtils.h"
#include "Patate/shelves.h"
#include <vector>
#include <algorithm>
#include <chrono> // std::chrono::seconds, std::chrono::milliseconds
// std::chrono::duration_cast
using namespace std;
using namespace Grenaille;
template<typename Scalar, int nbPoints, int nbSeeds>
void testFunction()
{
using namespace std::chrono;
using Time = std::chrono::high_resolution_clock;
using ms = std::chrono::milliseconds;
using KdTree = Shelves::KdTree<Scalar>;
KdTree tree (nbPoints);
using VectorType = typename KdTree::VectorType;
auto t00 = Time::now();
for (int i = 0; i != nbPoints; ++i){
tree.add(VectorType::Random());
}
tree.finalize();
auto t01 = Time::now();
auto t10 = Time::now();
KdTree tree2 (tree._getPoints().begin(), tree._getPoints().end());
auto t11 = Time::now();
std::cout << "Construction times (msec): per-element (" << std::chrono::duration_cast<ms>(t01-t00).count()
<< "), by copy of pre-ordered elements (" << std::chrono::duration_cast<ms>(t11-t10).count() << ")."
<< std::endl;
Scalar sqdist = 0.001;
// generate the seed, and compare kdtree search with bruteforce
std::list<VectorType, Eigen::aligned_allocator<VectorType> > resultsKd, resultsKd2;
for (int i = 0; i != nbSeeds; ++i){
VectorType seed = VectorType::Random();
tree.doQueryDist ( seed, sqdist, resultsKd );
tree2.doQueryDist( seed, sqdist, resultsKd2 );
for (const auto& q : tree._getPoints()){
if ( (q - seed).squaredNorm() <= sqdist ) {
auto it = std::find( resultsKd.begin(), resultsKd.end(), q ) ;
VERIFY ( it != resultsKd.end() );
resultsKd.erase( it );
it = std::find( resultsKd2.begin(), resultsKd2.end(), q ) ;
VERIFY ( it != resultsKd2.end() );
resultsKd2.erase( it );
}
}
VERIFY ( resultsKd.empty() );
VERIFY ( resultsKd2.empty() );
}
}
template<typename Scalar>
void callSubTests()
{
for(int i = 0; i < g_repeat; ++i)
{
CALL_SUBTEST(( testFunction<Scalar, 100000, 100>() ));
}
}
int main(int argc, char** argv)
{
if(!init_testing(argc, argv))
{
return EXIT_FAILURE;
}
cout << "Test Kdtree functions" << endl;
callSubTests<float>();
callSubTests<double>();
callSubTests<long double>();
cout << "Ok..." << endl;
}