more efficient ParticleTree::getParticles() and adding ParticleTree::getParticlesForUpdate()

This commit is contained in:
Andrew Meadows 2014-01-26 16:14:11 -08:00
parent daf11692d8
commit 31a2e467f4
5 changed files with 85 additions and 75 deletions

View file

@ -170,16 +170,14 @@ public:
bool ParticleTree::findInSphereOperation(OctreeElement* element, void* extraData) {
FindAllNearPointArgs* args = static_cast<FindAllNearPointArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(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<const Particle*> moreParticles = particleTreeElement->getParticles(args->position, args->targetRadius);
args->particles << moreParticles;
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(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<const Particle*> ParticleTree::findParticles(const glm::vec3& center, float radius) {
QVector<Particle*> result;
void ParticleTree::findParticles(const glm::vec3& center, float radius, QVector<const Particle*>& 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<Particle*> _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<ParticleTreeElement*>(element);
particleTreeElement->getParticlesForUpdate(args->_box, args->_foundParticles);
return true;
}
return false;
}
void ParticleTree::findParticlesForUpdate(const AABox& box, QVector<Particle*> 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<Particle*> _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<ParticleTreeElement*>(element);
particleTreeElement->findParticles(args->_box, args->_foundParticles);
return true;
}
return false;
}
void ParticleTree::findParticles(const AABox& box, QVector<Particle*> foundParticles) {
FindParticlesArgs args(box);
recurseTreeWithOperation(findOperation, &args);
// swap the two lists of particle pointers instead of copy
foundParticles.swap(args._foundParticles);
}

View file

@ -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<const Particle*> 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<const Particle*>& 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<Particle*> 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<Particle*> particles);
private:
static bool updateOperation(OctreeElement* element, void* extraData);

View file

@ -185,21 +185,34 @@ const Particle* ParticleTreeElement::getClosestParticle(glm::vec3 position) cons
return closestParticle;
}
QVector<const Particle*> ParticleTreeElement::getParticles(glm::vec3 searchPosition, float searchRadius) const {
QVector<const Particle*> results;
void ParticleTreeElement::getParticles(const glm::vec3& searchPosition, float searchRadius, QVector<const Particle*>& 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<Particle*>& foundParticles) {
QList<Particle>::iterator particleItr = _particles->begin();
QList<Particle>::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<Particle*>& foundParticles) {
QList<Particle>::iterator particleItr = _particles->begin();
QList<Particle>::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) {

View file

@ -89,15 +89,21 @@ public:
bool containsParticle(const Particle& particle) const;
bool updateParticle(const Particle& particle);
const Particle* getClosestParticle(glm::vec3 position) const;
QVector<const Particle*> 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<const Particle*>& 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<Particle*>& foundParticles);
/// \param particles[out] vector of non-const Particle*
void getParticlesForUpdate(const AABox& box, QVector<Particle*>& foundParticles);
const Particle* getParticleWithID(uint32_t id) const;
bool removeParticleWithID(uint32_t id);
protected:
virtual void init(unsigned char * octalCode);

View file

@ -150,7 +150,8 @@ ParticleID ParticlesScriptingInterface::findClosestParticle(const glm::vec3& cen
QVector<ParticleID> ParticlesScriptingInterface::findParticles(const glm::vec3& center, float radius) const {
QVector<ParticleID> result;
if (_particleTree) {
QVector<const Particle*> particles = _particleTree->findParticles(center/(float)TREE_SCALE, radius/(float)TREE_SCALE);
QVector<const Particle*> particles;
_particleTree->findParticles(center/(float)TREE_SCALE, radius/(float)TREE_SCALE, particles);
foreach (const Particle* particle, particles) {
ParticleID thisParticleID(particle->getID(), UNKNOWN_TOKEN, true);