From 31a2e467f4a00d8577d724fb168f7ff6f18fadc9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 26 Jan 2014 16:14:11 -0800 Subject: [PATCH] more efficient ParticleTree::getParticles() and adding ParticleTree::getParticlesForUpdate() --- libraries/particles/src/ParticleTree.cpp | 74 +++++++++---------- libraries/particles/src/ParticleTree.h | 20 +++-- .../particles/src/ParticleTreeElement.cpp | 47 ++++++------ libraries/particles/src/ParticleTreeElement.h | 16 ++-- .../src/ParticlesScriptingInterface.cpp | 3 +- 5 files changed, 85 insertions(+), 75 deletions(-) diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index d0e5060b4c..3e224be48b 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -170,16 +170,14 @@ public: bool ParticleTree::findInSphereOperation(OctreeElement* element, void* extraData) { FindAllNearPointArgs* args = static_cast(extraData); - ParticleTreeElement* particleTreeElement = static_cast(element); - glm::vec3 penetration; - bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position, + bool sphereIntersection = element->getAABox().findSpherePenetration(args->position, args->targetRadius, penetration); - // If this particleTreeElement contains the point, then search it... + // If this element contains the point, then search it... if (sphereIntersection) { - QVector moreParticles = particleTreeElement->getParticles(args->position, args->targetRadius); - args->particles << moreParticles; + ParticleTreeElement* particleTreeElement = static_cast(element); + particleTreeElement->getParticles(args->position, args->targetRadius, args->particles); return true; // keep searching in case children have closer particles } @@ -187,13 +185,43 @@ bool ParticleTree::findInSphereOperation(OctreeElement* element, void* extraData return false; } -QVector ParticleTree::findParticles(const glm::vec3& center, float radius) { - QVector result; +void ParticleTree::findParticles(const glm::vec3& center, float radius, QVector& foundParticles) { FindAllNearPointArgs args = { center, radius }; lockForRead(); recurseTreeWithOperation(findInSphereOperation, &args); unlock(); - return args.particles; + // swap the two lists of particle pointers instead of copy + foundParticles.swap(args.particles); +} + +class FindParticlesInBoxArgs { +public: + FindParticlesInBoxArgs(const AABox& box) + : _box(box), _foundParticles() { + } + + AABox _box; + QVector _foundParticles; +}; + +bool findInBoxForUpdateOperation(OctreeElement* element, void* extraData) { + FindParticlesInBoxArgs* args = static_cast< FindParticlesInBoxArgs*>(extraData); + const AABox& elementBox = element->getAABox(); + if (elementBox.touches(args->_box)) { + ParticleTreeElement* particleTreeElement = static_cast(element); + particleTreeElement->getParticlesForUpdate(args->_box, args->_foundParticles); + return true; + } + return false; +} + +void ParticleTree::findParticlesForUpdate(const AABox& box, QVector foundParticles) { + FindParticlesInBoxArgs args(box); + lockForRead(); + recurseTreeWithOperation(findInBoxForUpdateOperation, &args); + unlock(); + // swap the two lists of particle pointers instead of copy + foundParticles.swap(args._foundParticles); } class FindByIDArgs { @@ -495,31 +523,3 @@ void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const Hi recurseTreeWithOperation(findAndDeleteOperation, &args); } } - -class FindParticlesArgs { -public: - FindParticlesArgs(const AABox& box) - : _box(box), _foundParticles() { - } - - AABox _box; - QVector _foundParticles; -}; - -bool findOperation(OctreeElement* element, void* extraData) { - FindParticlesArgs* args = static_cast< FindParticlesArgs*>(extraData); - const AABox& elementBox = element->getAABox(); - if (elementBox.touches(args->_box)) { - ParticleTreeElement* particleTreeElement = static_cast(element); - particleTreeElement->findParticles(args->_box, args->_foundParticles); - return true; - } - return false; -} - -void ParticleTree::findParticles(const AABox& box, QVector foundParticles) { - FindParticlesArgs args(box); - recurseTreeWithOperation(findOperation, &args); - // swap the two lists of particle pointers instead of copy - foundParticles.swap(args._foundParticles); -} diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 44db78814c..a19bad9892 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -42,7 +42,19 @@ public: void storeParticle(const Particle& particle, Node* senderNode = NULL); const Particle* findClosestParticle(glm::vec3 position, float targetRadius); const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false); - QVector findParticles(const glm::vec3& center, float radius); + + /// finds all particles that touch a sphere + /// \param center the center of the sphere + /// \param radius the radius of the sphere + /// \param foundParticles[out] vector of const Particle* + /// \remark Side effect: any initial contents in foundParticles will be lost + void findParticles(const glm::vec3& center, float radius, QVector& foundParticles); + + /// finds all particles that touch a box + /// \param box the query box + /// \param foundParticles[out] vector of non-const Particle* + /// \remark Side effect: any initial contents in particles will be lost + void findParticlesForUpdate(const AABox& box, QVector foundParticles); void addNewlyCreatedHook(NewlyCreatedParticleHook* hook); void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook); @@ -54,12 +66,6 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const HifiSockAddr& senderSockAddr, Node* sourceNode); - /// finds all particles that touch a box - /// \param box the query box - /// \param particles[out] vector of Particle pointer - /// \remark Side effect: any initial contents in particles will be lost - void findParticles(const AABox& box, QVector particles); - private: static bool updateOperation(OctreeElement* element, void* extraData); diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index 0878436e31..72d3e1b7b0 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -185,21 +185,34 @@ const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) cons return closestParticle; } -QVector ParticleTreeElement::getParticles(glm::vec3 searchPosition, float searchRadius) const { - QVector results; +void ParticleTreeElement::getParticles(const glm::vec3& searchPosition, float searchRadius, QVector& foundParticles) const { uint16_t numberOfParticles = _particles->size(); for (uint16_t i = 0; i < numberOfParticles; i++) { const Particle* particle = &(*_particles)[i]; glm::vec3 particlePosition = particle->getPosition(); - float particleRadius = particle->getRadius(); - glm::vec3 penetration; - - // check to see that the particle (penetrator) penetrates the search area - if (findSphereSpherePenetration(particlePosition, particleRadius, searchPosition, searchRadius, penetration)) { - results << particle; + float distance = glm::length(particle->getPosition() - searchPosition); + if (distance < searchRadius + particle->getRadius()) { + foundParticles.push_back(particle); } } - return results; +} + +void ParticleTreeElement::getParticlesForUpdate(const AABox& box, QVector& foundParticles) { + QList::iterator particleItr = _particles->begin(); + QList::iterator particleEnd = _particles->end(); + AABox particleBox; + while(particleItr != particleEnd) { + Particle* particle = &(*particleItr); + float radius = particle->getRadius(); + // NOTE: we actually do box-box collision queries here, which is sloppy but good enough for now + // TODO: decide whether to replace particleBox-box query with sphere-box (requires a square root + // but will be slightly more accurate). + particleBox.setBox(particle->getPosition() - glm::vec3(radius), 2.f * radius); + if (particleBox.touches(_box)) { + foundParticles.push_back(particle); + } + ++particleItr; + } } const Particle* ParticleTreeElement::getParticleWithID(uint32_t id) const { @@ -228,22 +241,6 @@ bool ParticleTreeElement::removeParticleWithID(uint32_t id) { return foundParticle; } -void ParticleTreeElement::findParticles(const AABox& box, QVector& foundParticles) { - QList::iterator particleItr = _particles->begin(); - QList::iterator particleEnd = _particles->end(); - AABox particleBox; - while(particleItr != particleEnd) { - Particle* particle = &(*particleItr); - float radius = particle->getRadius(); - particleBox.setBox(particle->getPosition() - glm::vec3(radius), 2.f * radius); - // TODO: replace particleBox-box query with sphere-box - if (particleBox.touches(_box)) { - foundParticles.push_back(particle); - } - ++particleItr; - } -} - int ParticleTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { diff --git a/libraries/particles/src/ParticleTreeElement.h b/libraries/particles/src/ParticleTreeElement.h index e967d9bd23..1d30bfbdfd 100644 --- a/libraries/particles/src/ParticleTreeElement.h +++ b/libraries/particles/src/ParticleTreeElement.h @@ -89,15 +89,21 @@ public: bool containsParticle(const Particle& particle) const; bool updateParticle(const Particle& particle); const Particle* getClosestParticle(glm::vec3 position) const; - QVector getParticles(glm::vec3 position, float radius) const; - const Particle* getParticleWithID(uint32_t id) const; - bool removeParticleWithID(uint32_t id); + /// finds all particles that touch a sphere + /// \param position the center of the query sphere + /// \param radius the radius of the query sphere + /// \param particles[out] vector of const Particle* + void getParticles(const glm::vec3& position, float radius, QVector& foundParticles) const; /// finds all particles that touch a box /// \param box the query box - /// \param particles[out] vector of Particle pointers - void findParticles(const AABox& box, QVector& foundParticles); + /// \param particles[out] vector of non-const Particle* + void getParticlesForUpdate(const AABox& box, QVector& foundParticles); + + const Particle* getParticleWithID(uint32_t id) const; + + bool removeParticleWithID(uint32_t id); protected: virtual void init(unsigned char * octalCode); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 0641cdba7c..2bbade964d 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -150,7 +150,8 @@ ParticleID ParticlesScriptingInterface::findClosestParticle(const glm::vec3& cen QVector ParticlesScriptingInterface::findParticles(const glm::vec3& center, float radius) const { QVector result; if (_particleTree) { - QVector particles = _particleTree->findParticles(center/(float)TREE_SCALE, radius/(float)TREE_SCALE); + QVector particles; + _particleTree->findParticles(center/(float)TREE_SCALE, radius/(float)TREE_SCALE, particles); foreach (const Particle* particle, particles) { ParticleID thisParticleID(particle->getID(), UNKNOWN_TOKEN, true);