I'm honestly at a loss as to why my question is being called a duplicate as all the other examples show how to sort a variable within a struct. I am trying to sort a variable within a struct based on another, and this I cannot find examples of. Below is my question in the hopes someone can help:
I have a rudimentary particle system I've developed for learning.
My main particle is contained in a struct which looks like this:
struct Particle {
float px; // x-position
float py; // y-position
float pz; // z-position
float scale;
float rotation;
float red;
float green;
float blue;
float alpha;
int index; };
Index is the particle ID. As I create each new particle, it gets saved into the Particle vector array called std::vector<Particle> particles; which I increment by one. Finally, I draw them after that.
I now want to introduce a pass for depth sorting, so that I can draw the particles from furthest to closest.
I understand that std::sort will work. My understanding is that I need to loop through the particles.pz (z position) but apply that sorting result to particles.index. So the index will ultimately be rearranged and hold the correct drawing order. I have this working already but not using std::sort and it is painfully slow. Thus, I'm hoping std::sort will provide a boost in performance.
I see that to do that, you can sort through the struct like this:
std::sort(particles.begin(), particles.end(), [](const auto& lhs, const auto& rhs)
{
return lhs.pz1 > rhs.pz1;
});
But this will rearrange the z positions whereas I want to rearrange the particle index BASED on the z position sort. I've looked at many other examples but none seem to address this.
I am not so experienced with structs, let alone sorting, so obviously I am doing something wrong.
How can I modify this code so that it sorts through the particle z positions from furthest to closest, and applies that sorting to the particle index?
ADDENDUM:
Perhaps this will help. This code shows my current sorting algorithm and how it works. I am trying to optimize this and see if std::sort can perform better. This is before I was using my struct so the variables are named differently and I hope I copied it correctly but it is mainly for illustrative purposes. (Counter is total particles).
for (int i = 0; i < counter - 1; ++i) {
for (int j = 0; j < counter - 1; ++j) {
int p = particles[j].index;
int q = particles[j + 1].index;
if ( particles[p].pz > particles[q].pz) {
unsigned int tmp = particles[j].index;
particles[j].index = particles[j + 1].index;
particles[j + 1].index = tmp;
}
}
}
CONCLUSION:
@PaulMcKenzie was able to help me understand and solve this. He went the extra mile to write out example code which I will post below as my accepted answer. After having to do some minor adjustments, I can confirm his solution works and it is much faster. Whereas my tests came in at 16 seconds of computation his solution using std::sort brought it down to 3.8 seconds. Thanks again!
#include <algorithm>
#include <vector>
#include <numeric>
#include <iostream>
#include <random>
struct Particle {
float px; // x-position
float py; // y-position
float pz; // z-position
float scale;
float rotation;
float red;
float green;
float blue;
float alpha;
};
int main()
{
// random number generator
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> zValues(1.0f, 1000.0f);
// Fill vector with random z values
std::vector<Particle> vParticles(10);
for (auto& v : vParticles )
v.pz = zValues(gen);
std::vector<int> index(10);
std::cout << "Original order by z:\n";
for (auto& v : vParticles)
std::cout << v.pz << "\n";
// set up index array
std::iota(index.begin(), index.end(), 0);
// Sort via the index
std::sort(index.begin(), index.end(), [&](int n1, int n2)
{ return vParticles[n1].pz < vParticles[n2].pz;});
std::cout << "\nSorted order by z:\n";
for (auto& i : index)
std::cout << vParticles[i].pz << " " << " is at index " << i << "\n";
std::cout << "\nHere is the final index array:\n";
for (auto& i : index)
std::cout << i << "\n";
std::cout << "\nProof that vector has not changed:\n";
for (auto& v : vParticles)
std::cout << v.pz << "\n";
}
@PaulMcKenzie was able to help me understand and solve this. He went the extra mile to write out example code which I will post below as my accepted answer. After having to do some minor adjustments, I can confirm his solution works and it is much faster. Whereas my tests came in at 16 seconds of computation his solution using std::sort brought it down to 3.8 seconds. Thanks again!