0

Here's the code in question:

public void calculate() {
        // Center of circle is at (250, 250).
        //THIS ALGORITHM IS NOW PROVEN TO BE WORSE THAN I FEARED...

        /*      What it does:
         *          Moves object around in a circle.
         *          Does not move the object towards the center.
         *          Object always stays on the rim of the circle.
         * 
         *      Algorithm I used. (DOES NOT WORK):
         *          N is normalized vector. 
         *          R = -2*(V dot N)*N + V
         */

        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        double nx = x - 250;
        double ny = y - 250;
        double nd = Math.hypot(nx, ny);
        if (nd == 0)
            nd = 1;
        nx /= nd;
        ny /= nd;
        double dotProduct = vx * nx + vy * ny;
        vx += (float) (-2 * dotProduct * nx);
        vy += (float) (-2 * dotProduct * ny);
        x -= vx * 2;
        y -= vy * 2;
        vx *= 0.99;
        vy *= 0.99;
    }

And this is what happens.

Picture.

The black line you see is where the purple object (box) moves. It just so happens to be right on the circle line I drew with Canvas.drawCircle().

I don't understand why reflection didn't work. If an object is to hit a circular wall, shouldn't it reflect the object's direction of velocity, which is what the algorithm was meant to be? Or I used the wrong algorithm?

Any help is appreciated. Thanks in advance.

Machavity
  • 30,841
  • 27
  • 92
  • 100
tom_mai78101
  • 2,383
  • 2
  • 32
  • 59
  • What are your initial conditions and how exactly does the trajectory evolve from them? If you start from the rim, that's where the dot will stay, but if you start from the center, then **something** must happen upon touching the rim. What happens? – Marko Topolnik Aug 20 '12 at 15:53
  • 1
    You have lost a minus sign somewhwre in the formula. – n. m. could be an AI Aug 20 '12 at 15:55
  • @MarkoTopolnik If I start off inside the circle, the object will move closer and closer towards the center, and then spins around rapidly. It spins until the friction I have given stops the object's velocity. If I keep the object accelerating towards a given direction, the object will eventually come to a point where its acceleration and velocity keeps the object **on** the circular rim, regardless if the object is outside of the circle or not. I'd tell you more, but it will get weirder and weirder. – tom_mai78101 Aug 21 '12 at 05:13
  • @n.m. Really??? I don't see it. I followed the algorithm given in the code comment section, and I don't see anything in the code that's not matching the algorithm. If you meant the velocity subtracting the position, that part is correct. There are some APIs out there that uses reversed axes, and I'm using one of them APIs. – tom_mai78101 Aug 21 '12 at 05:16
  • WTF?!?! Today, I just $%#% realized how stupid I am. This algorithm is for Circle to Object, **OUTSIDE OF CIRCLE AND HITTING THE CIRCLE FROM OUTSIDE**, Collision Response. Even worse, this algorithm is better than the PDF version, which was unexpected when I compare the two. Man, I am so angry, and realized how I wasted a few months of work way before all this, and right now I'm crying of agony. – tom_mai78101 Aug 21 '12 at 10:31
  • And there's more. It's like putting a gram of salt on my wound. I followed what @n.m. told me, and reversed a boolean sign (which technically, isn't a minus sign.) and have a successful Circle to Object, **OBJECT INSIDE OF CIRCLE AND HITTING THE CIRCLE FROM INSIDE**, Collision Response, and it's working like magic. $%# Me for wasting all of your time. I felt bad, and wanted to make up for all of this. – tom_mai78101 Aug 21 '12 at 10:35

3 Answers3

2

Can you do bouncing off a straight wall of arbitrary angle? That should be the first step. (You may find that a polar representation of the velocity vector is easier to work with.)

Once you've got that working, it should be fairly straightforward: bouncing off a circle is like bouncing off a tangent of that circle that touches it at the point of contact.

You can calculate this tangent by observing that it's perpendicular to the radius vector in the point of contact (that is the vector that points from where the object is to the centre of the circle)

biziclop
  • 48,926
  • 12
  • 77
  • 104
2

Is there a vector-based implementation of this, without relying on angles?

Yes, see 2-Dimensional Elastic Collisions without Trigonometry, illustrated in this KineticModel. Your implementation appears to be missing the tangential component. See Ensemble#collideAtoms() for details.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I had just checked on the tangential component. Unfortunately, I don't know what's going on. There's a weird effect that causes the object to move towards outside if the object rotates around inside the circle at high speed, and it went off the screen. I double-checked the PDF, followed the PDF instructions, did some calculations, but I just couldn't find the problem. I give you credit for giving me a bonus midnight story book to read. :D – tom_mai78101 Aug 21 '12 at 10:41
1

This is what I've got, and I'm going to share my findings to all of you.

public void calculate() {
    // Center of circle is at (250, 250). Radius is 40.
    //THIS ALGORITHM IS PROVEN TO BE BETTER THAN I FEARED...

    /*      What it does:
     *          Moves object around in a circle, if object is 
     *              inside of circle.
     *          Does not move the object towards the center, 
     *              nor outwards. This is crucial.
     *          Object always stays on the rim of the circle, 
     *              if the collision detection allows it to.
     * 
     *      Algorithm I used. (DOES WORK, NOT EXPECTING THIS THOUGH.):
     *          N is normalized vector. 
     *          R = -2*(V dot N)*N + V
     */



    double nx = x - 250;
    double ny = y - 250;
    double nd = Math.hypot(nx, ny);
    if (nd < 40){
        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        x -= vx;
        y -= vy;
        vx *= 0.9;
        vy *= 0.9;
        return;
    }

    vx += Accelero.X * 0.1;
    vy += Accelero.Y * 0.1;


    if (nd == 0)
        nd = 1;
    nx /= nd;
    ny /= nd;
    double dotProduct = vx * nx + vy * ny;
    vx += (float) (-2 * dotProduct * nx);
    vy += (float) (-2 * dotProduct * ny);
    x -= vx * 2;
    y -= vy * 2;
    vx *= 0.99;
    vy *= 0.99;
}

I embedded a collision detection inside my function, basically making this function not as efficient as possible. Ignore that, for it's not the main focus.

The circle's radius is 40, the (x,y) position is (250,250).

Only when the object is either on the circle, or further away from the center of circle, should we calculate the collision response, which is given by the algorithm R = -2*(V dot N)*N + V, where normal vector N is already normalized.

The algorithm is indeed correct, it's the boolean condition of my collision detection is what causes the object to stay on the rim of the circle and go round-a-bout on it.

I didn't say the other algorithm, which @trashgod had provided is wrong. It's because of some weird issue that somehow causes the object to move unusually. I would guess it's the API I'm using's fault, which it didn't allow doubles, but I may be incorrect. I just couldn't find the source of the problem. Which I'm also happy to not look into it further anymore.

The collision detection boolean condition itself could change everything, if it was slightly altered. If it wasn't for @n.m. pointing that I somehow seemed to forget a minus sign (in this case, a NOT sign), I probably would never realized how trivial it would be.

tom_mai78101
  • 2,383
  • 2
  • 32
  • 59
  • Yes, overshoot is a problem. The [`Boucescope`](http://www.vobarian.com/collisions/) example also addresses this. – trashgod Aug 21 '12 at 12:46