From f98959f92aac387929cec8e8888edecbe35102ab Mon Sep 17 00:00:00 2001 From: Matt Williams Date: Wed, 1 May 2013 22:28:46 +0100 Subject: [PATCH] Add a new pickVoxel function. Hopefully this pickVoxel function will fulfil most most need with raycasting which aren't covered by the existing raycast functions. It's essentially a wrapper around the current functions, using a custom functor to store the position of a solid voxel as well as the previous empty voxel. It doesn't require the user to provide a functor of their own, just the value that they've assigned to empty voxels. As well as the function itself, we also have a unit test as well as it being built in the bindings. --- library/PolyVoxCore/CMakeLists.txt | 2 + .../PolyVoxCore/include/PolyVoxCore/Picking.h | 48 +++++++++++ .../include/PolyVoxCore/Picking.inl | 84 +++++++++++++++++++ library/bindings/Picking.i | 8 ++ library/bindings/PolyVoxCore.i | 1 + tests/CMakeLists.txt | 4 + tests/TestPicking.cpp | 67 +++++++++++++++ tests/TestPicking.h | 37 ++++++++ 8 files changed, 251 insertions(+) create mode 100644 library/PolyVoxCore/include/PolyVoxCore/Picking.h create mode 100644 library/PolyVoxCore/include/PolyVoxCore/Picking.inl create mode 100644 library/bindings/Picking.i create mode 100644 tests/TestPicking.cpp create mode 100644 tests/TestPicking.h diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index 145484dd..b9cdf8c4 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -75,6 +75,8 @@ SET(CORE_INC_FILES include/PolyVoxCore/MaterialDensityPair.h include/PolyVoxCore/MinizCompressor.h include/PolyVoxCore/PolyVoxForwardDeclarations.h + include/PolyVoxCore/Picking.h + include/PolyVoxCore/Picking.inl include/PolyVoxCore/RawVolume.h include/PolyVoxCore/RawVolume.inl include/PolyVoxCore/RawVolumeSampler.inl diff --git a/library/PolyVoxCore/include/PolyVoxCore/Picking.h b/library/PolyVoxCore/include/PolyVoxCore/Picking.h new file mode 100644 index 00000000..15360bb0 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Picking.h @@ -0,0 +1,48 @@ +/******************************************************************************* +Copyright (c) 2013 Matt Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#ifndef __PolyVox_Picking_H__ +#define __PolyVox_Picking_H__ + +#include "PolyVoxCore/Vector.h" + +namespace PolyVox +{ + /** + * A structure containing the information about a picking operation + */ + struct PickResult + { + bool didHit; ///< Did the picking operation hit anything + Vector3DInt32 hitVoxel; ///< The location of the solid voxel it hit + Vector3DInt32 previousVoxel; ///< The location of the voxel before the one it hit + }; + + /// Pick the first solid voxel along a vector + template + PickResult pickVoxel(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, const typename VolumeType::VoxelType& emptyVoxelExample = typename VolumeType::VoxelType()); +} + +#include "PolyVoxCore/Picking.inl" + +#endif //__PolyVox_Picking_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/Picking.inl b/library/PolyVoxCore/include/PolyVoxCore/Picking.inl new file mode 100644 index 00000000..3bbbdaf3 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Picking.inl @@ -0,0 +1,84 @@ +/******************************************************************************* +Copyright (c) 2013 Matt Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#include "PolyVoxCore/Raycast.h" + +namespace PolyVox +{ + namespace + { + /** + * This is just an implementation class for the pickVoxel function + * + * It makes note of the sort of empty voxel you're looking for in the constructor. + * + * Each time the operator() is called: + * * if it's hit a voxel it sets up the result and returns false + * * otherwise it preps the result for the next iteration and returns true + */ + template + class RaycastPickingFunctor + { + public: + RaycastPickingFunctor(const typename VolumeType::VoxelType& emptyVoxelExample) + :m_emptyVoxelExample(emptyVoxelExample) + ,m_result{false} + { + } + + bool operator()(const typename VolumeType::Sampler& sampler) + { + if(sampler.getVoxel() != m_emptyVoxelExample) //If we've hit something + { + m_result.didHit = true; + m_result.hitVoxel = sampler.getPosition(); + return false; + } + + m_result.previousVoxel = sampler.getPosition(); + + return true; + } + const typename VolumeType::VoxelType& m_emptyVoxelExample; + PickResult m_result; + }; + } + + /** + * \param volData The volume to pass the ray though + * \param v3dStart The start position in the volume + * \param v3dDirectionAndLength The direction and length of the ray + * \param emptyVoxelExample The value used to represent empty voxels in your volume + * + * \return A PickResult containing the hit information + */ + template + PickResult pickVoxel(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, const typename VolumeType::VoxelType& emptyVoxelExample) + { + RaycastPickingFunctor functor(emptyVoxelExample); + + RaycastResult raycastResult = raycastWithDirection(volData, v3dStart, v3dDirectionAndLength, functor); + + return functor.m_result; + } +} diff --git a/library/bindings/Picking.i b/library/bindings/Picking.i new file mode 100644 index 00000000..17099299 --- /dev/null +++ b/library/bindings/Picking.i @@ -0,0 +1,8 @@ +%module Picking +%{ +#include "Picking.h" +%} + +%include "Picking.h" + +EXTRACTORS(pickVoxel) diff --git a/library/bindings/PolyVoxCore.i b/library/bindings/PolyVoxCore.i index 10a6b1ee..bb693c47 100644 --- a/library/bindings/PolyVoxCore.i +++ b/library/bindings/PolyVoxCore.i @@ -90,3 +90,4 @@ EXTRACTOR(shortname, LargeVolume) %include "CubicSurfaceExtractor.i" %include "CubicSurfaceExtractorWithNormals.i" %include "Raycast.i" +%include "Picking.i" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3224d165..a1dc35ac 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -89,6 +89,10 @@ ADD_TEST(MaterialTestCompile ${LATEST_TEST} testCompile) CREATE_TEST(TestRaycast.h TestRaycast.cpp TestRaycast) ADD_TEST(RaycastExecuteTest ${LATEST_TEST} testExecute) +# Picking tests +CREATE_TEST(TestPicking.h TestPicking.cpp TestPicking) +ADD_TEST(PickingExecuteTest ${LATEST_TEST} testExecute) + # Region tests CREATE_TEST(TestRegion.h TestRegion.cpp TestRegion) ADD_TEST(RegionEqualityTest ${LATEST_TEST} testEquality) diff --git a/tests/TestPicking.cpp b/tests/TestPicking.cpp new file mode 100644 index 00000000..62fa8531 --- /dev/null +++ b/tests/TestPicking.cpp @@ -0,0 +1,67 @@ +/******************************************************************************* +Copyright (c) 2013 Matt Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#include "TestPicking.h" + +#include "PolyVoxCore/Picking.h" +#include "PolyVoxCore/SimpleVolume.h" + +#include + +using namespace PolyVox; + +void TestPicking::testExecute() +{ + const int32_t uVolumeSideLength = 32; + + SimpleVolume volData(Region(Vector3DInt32(0,0,0), Vector3DInt32(uVolumeSideLength-1, uVolumeSideLength-1, uVolumeSideLength-1))); + for (int32_t z = 0; z < uVolumeSideLength; z++) + { + for (int32_t y = 0; y < uVolumeSideLength; y++) + { + for (int32_t x = 0; x < uVolumeSideLength; x++) + { + if((x > uVolumeSideLength/2)) //x > 16 is filled + { + volData.setVoxelAt(x, y, z, 100); + } + else + { + volData.setVoxelAt(x, y, z, 0); + } + } + } + } + + PickResult resultHit = pickVoxel(&volData, Vector3DFloat(0, uVolumeSideLength / 2, uVolumeSideLength / 2), Vector3DFloat(uVolumeSideLength, 0, 0)); + + QCOMPARE(resultHit.didHit, true); + QCOMPARE(resultHit.hitVoxel, Vector3DInt32((uVolumeSideLength / 2) + 1, uVolumeSideLength / 2, uVolumeSideLength / 2)); + QCOMPARE(resultHit.previousVoxel, Vector3DInt32((uVolumeSideLength / 2), uVolumeSideLength / 2, uVolumeSideLength / 2)); + + PickResult resultMiss = pickVoxel(&volData, Vector3DFloat(0, uVolumeSideLength / 2, uVolumeSideLength / 2), Vector3DFloat(uVolumeSideLength / 2, uVolumeSideLength, uVolumeSideLength)); + + QCOMPARE(resultMiss.didHit, false); +} + +QTEST_MAIN(TestPicking) diff --git a/tests/TestPicking.h b/tests/TestPicking.h new file mode 100644 index 00000000..3ad62e66 --- /dev/null +++ b/tests/TestPicking.h @@ -0,0 +1,37 @@ +/******************************************************************************* +Copyright (c) 2013 Matt Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#ifndef __PolyVox_TestRaycast_H__ +#define __PolyVox_TestRaycast_H__ + +#include + +class TestPicking: public QObject +{ + Q_OBJECT + + private slots: + void testExecute(); +}; + +#endif