views:

354

answers:

8

I want to be able to move a particle in a straight line within a 3D environment but I can't think how to work out the next location based on two points within a 3D space?

I have created a struct which represents a particle which has a location and a next location? Would this be suitable to work out the next location to move too? I know how to initially set the next location using the following method:

// Set particle's direction to a random direction
void setDirection(struct particle *p)
{
    float xnm = (p->location.x * -1) - p->velocity;
    float xnp = p->location.x + p->velocity;
    float ynm = (p->location.y * -1) - p->velocity;
    float ynp = p->location.y + p->velocity;
    float znm = (p->location.z * -1) - p->velocity;
    float znp = p->location.z + p->velocity;

    struct point3f nextLocation = { randFloat(xnm, xnp), randFloat(ynm, ynp), randFloat(znm, znp) };
    p->nextLocation = nextLocation;
}

The structs I have used are:

// Represents a 3D point
struct point3f
{
    float x;
    float y;
    float z;
};

// Represents a particle
struct particle
{
    enum TYPES type;
    float radius;
    float velocity;
    struct point3f location;
    struct point3f nextLocation;
    struct point3f colour;
};

Am I going about this completely the wrong way?

here's all my code http://pastebin.com/m469f73c2

A: 

You want to implement the vector math X_{i+1} = X_{i} + Vt. For the Xs and V vectors representing position and velocity respectively, and t representing time. I've parameterized the distance along the track by time because I'm a physicist, but it really is the natural thing to do. Normalize the velocity vector if you want to give track distance (i.e. scale V such that V.x*V.x + V.y*V.y + V.z*V.z = 1).

Using the struct above makes it natural to access the elements, but not so convenient to do the addition: arrays are better for that. Like this:

double X[3];
double V[3];

// initialize

for (int i=0; i<3 ++1){
  X[i] = X[i] + V[i]*t;
}

With a union, you can get the advantages of both:

struct vector_s{
  double x;
  double y;
  double z;
}
typedef
union vector_u {
  struct vector_s s; // s for struct
  double a[3];       // a for array
} vector;


If you want to associate both the position and the velocity of with the particle (a very reasonable thing to do) you construct a structure that support two vectors

typedef
struct particle_s {
  vector position;
  vector velocity;
  //...
} particle_t;

and run an update routine that looks roughly like:

void update(particle *p, double dt){
  for (int i=0; i<3 ++i){
    p->position.a[i] += p->velocity.a[i]*dt;
  }
}
dmckee
Would you care to explain this in a bit more detail? I am a unsure of what you mean exactly.
Malachi
+1  A: 

Think of physics. An object has a position (x, y, z) and a movement vector (a, b, c). Your object should exist at its position; it has a movement vector associated with it that describes its momentum. In the lack of any additional forces on the object, and assuming that your movement vector describes the movement over a time period t, the position of your object at time x will be (x + (a*t), y + (b*t), z + (c*t)).

In short; don't store the current position and the next position. Store the current position and the object's momentum. It's easy enough to "tick the clock" and update the location of the object by simply adding the momentum to the position.

McWafflestix
+1  A: 

Store velocity as a struct point3f, and then you have something like this:

void move(struct particle * p)
{
  p->position.x += p->velocity.x;
  p->position.y += p->velocity.y;
  p->position.z += p->velocity.z;
}

Essentially the velocity is how much you want the position to change each second/tick/whatever.

Iceman
+3  A: 

I'd suggest that a particle should only have one location member -- the current location. Also, the velocity should ideally be a vector of 3 components itself. Create a function (call it move, displace whatever) that takes a particle and a time duration t. This will compute the final position after t units of time has elapsed:

struct point3f move(struct *particle, int time) {
    particle->location->x = particle->velocity->x * t;
    /* and so on for the other 2 dimensions */
    return particle->location;
}
dirkgently
+3  A: 

The other answer is a little mathish, it's actually pretty straight forward.

You need a "Velocity" which you are moving. It also has x, y and z coordinates.

In one time period, to move you just add the x velocity to your x position to get your new x position, repeat for y and z.

On top of that, you can have an "Acceleration" (also x,y,z) For instance, your z acceleration could be gravity, a constant.

Every time period your velocity should be recalcualted in the same way, Call velocity x "vx", so vx should become vx + ax, repeat for y and z (again).

It's been a while since math, but that's how I remember it, pretty straight forward unless you need to keep track of units, then it gets a little more interesting (but still not bad)

Bill K
The tricky part is to figure out the correct direction to move in. After that it should be cake.
Tim Lin
Actually, the tricky part is that in reality, there is a hole because this is done in finite "steps". To get real-world movement, you have to make the steps very close together. When you make them infinitely close together, you have a true model. There is an entire branch of math based on this idea of making the steps perfectly continuous (Calculus), but doing it in finite steps like this is a good approximation and simplifies the formulas a LOT.
Bill K
+2  A: 

I would recomend two things:

  1. read an article or two on basic vector math for animation. For instance, this is a site that explains 2d vectors for flash.

  2. start simple, start with a 1d point, ie a point only moving along x. Then try adding a second dimension (a 2d point in a 2d space) and third dimension. This might help you get a better understanding of the underlying mechanics. hope this helps

david h
A: 

Afaik, there are mainly two ways on how you can calculate the new position. One is like the other have explaint to use an explicit velocity. The other possibility is to store the last and the current position and to use the Verlet integration. Both ways have their advantages and disadvantages. You might also take a look on this interresting page.

quinmars
A: 

If you are trying to move along a straight line between two points, you can use the interpolation formula:

P(t) = P1*(1-t) + P2*t

P(t) is the calculated position of the point, t is a scalar ranging from 0 to 1, P1 and P2 are the endpoints, and the addition in the above is vector addition (so you apply this formula separately to the x, y and z components of your points). When t=0, you get P1; when t=1, you get P2, and for intermediate values, you get a point part way along the line between P1 and P2. So t=.5 gives you the midpoint between P1 and P2, t=.333333 gives you the point 1/3 of the way from P1 to P2, etc. Values of t outside the range [0, 1] extrapolate to points along the line outside the segment from P1 to P2.

Using the interpolation formula can be better than computing a velocity and repeatedly adding it if the velocity is small compared to the distance between the points, because you limit the roundoff error.

dewtell