Calculate next position and velocity after “bounce”

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












Intro and code



I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max].



public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) 
if (position + velocity < 0)
return TwoVector.<Double>builder()
.x(Math.abs(position + velocity))
.y(Math.abs(velocity))
.build();

if (position + velocity > max)
return TwoVector.<Double>builder()
.x(max - ((position + velocity) % max))
.y(-Math.abs(velocity))
.build();

return TwoVector.<Double>builder()
.x(position + velocity)
.y(velocity)
.build();



Explanation



  • The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".

  • The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".

  • If neither condition is true, we can add the current velocity to the current position to get the next position without issue.

Question



Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?







share|improve this question



























    up vote
    1
    down vote

    favorite












    Intro and code



    I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max].



    public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) 
    if (position + velocity < 0)
    return TwoVector.<Double>builder()
    .x(Math.abs(position + velocity))
    .y(Math.abs(velocity))
    .build();

    if (position + velocity > max)
    return TwoVector.<Double>builder()
    .x(max - ((position + velocity) % max))
    .y(-Math.abs(velocity))
    .build();

    return TwoVector.<Double>builder()
    .x(position + velocity)
    .y(velocity)
    .build();



    Explanation



    • The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".

    • The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".

    • If neither condition is true, we can add the current velocity to the current position to get the next position without issue.

    Question



    Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?







    share|improve this question























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      Intro and code



      I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max].



      public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) 
      if (position + velocity < 0)
      return TwoVector.<Double>builder()
      .x(Math.abs(position + velocity))
      .y(Math.abs(velocity))
      .build();

      if (position + velocity > max)
      return TwoVector.<Double>builder()
      .x(max - ((position + velocity) % max))
      .y(-Math.abs(velocity))
      .build();

      return TwoVector.<Double>builder()
      .x(position + velocity)
      .y(velocity)
      .build();



      Explanation



      • The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".

      • The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".

      • If neither condition is true, we can add the current velocity to the current position to get the next position without issue.

      Question



      Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?







      share|improve this question













      Intro and code



      I have the following function that calculates an objects "next" position and velocity (in 1 dimension) given a boundary [0, max].



      public TwoVector<Double> getNextPositionAndVelocity(double position, double velocity, double max) 
      if (position + velocity < 0)
      return TwoVector.<Double>builder()
      .x(Math.abs(position + velocity))
      .y(Math.abs(velocity))
      .build();

      if (position + velocity > max)
      return TwoVector.<Double>builder()
      .x(max - ((position + velocity) % max))
      .y(-Math.abs(velocity))
      .build();

      return TwoVector.<Double>builder()
      .x(position + velocity)
      .y(velocity)
      .build();



      Explanation



      • The first condition checks if adding the current velocity to the current position would cause the object to be beyond the "left" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the left boundary added to the left boundary and the next velocity should point the object to the "right".

      • The second condition checks if adding the current velocity to the current position would cause the object to beyond the "right" boundary. If that's the case, the next position should be equal to the amount the object would be beyond the boundary subtracted from the boundary and the next velocity should point the object to the "left".

      • If neither condition is true, we can add the current velocity to the current position to get the next position without issue.

      Question



      Are there more straightforward functions to calculate each of these "next" values? Perhaps a function that "collapses" these branches?









      share|improve this question












      share|improve this question




      share|improve this question








      edited Apr 28 at 21:37









      200_success

      123k14142399




      123k14142399









      asked Apr 28 at 20:58









      geofflittle

      825




      825




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          0
          down vote













          I.



          x(max - ((position + velocity) % max))


          doesn't look quite right. % max does not help here much (see below) it is better replaced with - max, and thus the whole formula turns into 2 * max - (position + velocity).



          II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity) is always LE than max?






          share|improve this answer




























            up vote
            0
            down vote















            I assume "next" in getNextPositionAndVelocity means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.



            As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:



            public double getNextPositionAndVelocity(double position, double velocity, double max) 
            double remainingDistance = Math.abs(velocity);
            double currentVelocity = velocity;
            double currentPosition = position;

            while (remainingDistance > 0.0)
            double nextBoundary;
            if (currentVelocity < 0.0)
            nextBoundary = 0.0;
            else
            assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
            nextBoundary = max;


            double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);

            if (maximumDistanceToTravelInCurrentDirection <= remainingDistance)
            currentPosition = nextBoundary;
            remainingDistance -= maximumDistanceToTravelInCurrentDirection;
            currentVelocity *= -1;
            else
            currentPosition += remainingDistance * Math.signum(currentVelocity);
            remainingDistance = 0;



            return new doublecurrentPosition, currentVelocity;



            Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.



            The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.



            Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position lies within the permitted range), but also handling special cases like the infinities or Double.NaN. E.g., if you check whether position >= 0 && position <= max, then you automatically have NaN covered for position and max, because the comparison operators and the equality operator == always return false if one operand is NaN (even Double.NaN == Double.NaN returns false, which is why there's a method Double.isNaN(double)), but position might still be Double.POSITIVE_INFINITY if max is also Double.POSITIVE_INFINITY. Also, max should probably be greater than 0 (which would not be covered by the aforementioned condition either).






            share|improve this answer





















              Your Answer




              StackExchange.ifUsing("editor", function ()
              return StackExchange.using("mathjaxEditing", function ()
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              );
              );
              , "mathjax-editing");

              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "196"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              convertImagesToLinks: false,
              noModals: false,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );








               

              draft saved


              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193165%2fcalculate-next-position-and-velocity-after-bounce%23new-answer', 'question_page');

              );

              Post as a guest






























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              0
              down vote













              I.



              x(max - ((position + velocity) % max))


              doesn't look quite right. % max does not help here much (see below) it is better replaced with - max, and thus the whole formula turns into 2 * max - (position + velocity).



              II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity) is always LE than max?






              share|improve this answer

























                up vote
                0
                down vote













                I.



                x(max - ((position + velocity) % max))


                doesn't look quite right. % max does not help here much (see below) it is better replaced with - max, and thus the whole formula turns into 2 * max - (position + velocity).



                II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity) is always LE than max?






                share|improve this answer























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  I.



                  x(max - ((position + velocity) % max))


                  doesn't look quite right. % max does not help here much (see below) it is better replaced with - max, and thus the whole formula turns into 2 * max - (position + velocity).



                  II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity) is always LE than max?






                  share|improve this answer













                  I.



                  x(max - ((position + velocity) % max))


                  doesn't look quite right. % max does not help here much (see below) it is better replaced with - max, and thus the whole formula turns into 2 * max - (position + velocity).



                  II. Do you assume large velocities are impossible, in other words, in the first alternative, can you guarantee that Math.abs(position + velocity) is always LE than max?







                  share|improve this answer













                  share|improve this answer



                  share|improve this answer











                  answered Apr 28 at 22:30









                  bipll

                  3926




                  3926






















                      up vote
                      0
                      down vote















                      I assume "next" in getNextPositionAndVelocity means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.



                      As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:



                      public double getNextPositionAndVelocity(double position, double velocity, double max) 
                      double remainingDistance = Math.abs(velocity);
                      double currentVelocity = velocity;
                      double currentPosition = position;

                      while (remainingDistance > 0.0)
                      double nextBoundary;
                      if (currentVelocity < 0.0)
                      nextBoundary = 0.0;
                      else
                      assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
                      nextBoundary = max;


                      double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);

                      if (maximumDistanceToTravelInCurrentDirection <= remainingDistance)
                      currentPosition = nextBoundary;
                      remainingDistance -= maximumDistanceToTravelInCurrentDirection;
                      currentVelocity *= -1;
                      else
                      currentPosition += remainingDistance * Math.signum(currentVelocity);
                      remainingDistance = 0;



                      return new doublecurrentPosition, currentVelocity;



                      Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.



                      The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.



                      Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position lies within the permitted range), but also handling special cases like the infinities or Double.NaN. E.g., if you check whether position >= 0 && position <= max, then you automatically have NaN covered for position and max, because the comparison operators and the equality operator == always return false if one operand is NaN (even Double.NaN == Double.NaN returns false, which is why there's a method Double.isNaN(double)), but position might still be Double.POSITIVE_INFINITY if max is also Double.POSITIVE_INFINITY. Also, max should probably be greater than 0 (which would not be covered by the aforementioned condition either).






                      share|improve this answer

























                        up vote
                        0
                        down vote















                        I assume "next" in getNextPositionAndVelocity means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.



                        As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:



                        public double getNextPositionAndVelocity(double position, double velocity, double max) 
                        double remainingDistance = Math.abs(velocity);
                        double currentVelocity = velocity;
                        double currentPosition = position;

                        while (remainingDistance > 0.0)
                        double nextBoundary;
                        if (currentVelocity < 0.0)
                        nextBoundary = 0.0;
                        else
                        assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
                        nextBoundary = max;


                        double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);

                        if (maximumDistanceToTravelInCurrentDirection <= remainingDistance)
                        currentPosition = nextBoundary;
                        remainingDistance -= maximumDistanceToTravelInCurrentDirection;
                        currentVelocity *= -1;
                        else
                        currentPosition += remainingDistance * Math.signum(currentVelocity);
                        remainingDistance = 0;



                        return new doublecurrentPosition, currentVelocity;



                        Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.



                        The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.



                        Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position lies within the permitted range), but also handling special cases like the infinities or Double.NaN. E.g., if you check whether position >= 0 && position <= max, then you automatically have NaN covered for position and max, because the comparison operators and the equality operator == always return false if one operand is NaN (even Double.NaN == Double.NaN returns false, which is why there's a method Double.isNaN(double)), but position might still be Double.POSITIVE_INFINITY if max is also Double.POSITIVE_INFINITY. Also, max should probably be greater than 0 (which would not be covered by the aforementioned condition either).






                        share|improve this answer























                          up vote
                          0
                          down vote










                          up vote
                          0
                          down vote











                          I assume "next" in getNextPositionAndVelocity means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.



                          As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:



                          public double getNextPositionAndVelocity(double position, double velocity, double max) 
                          double remainingDistance = Math.abs(velocity);
                          double currentVelocity = velocity;
                          double currentPosition = position;

                          while (remainingDistance > 0.0)
                          double nextBoundary;
                          if (currentVelocity < 0.0)
                          nextBoundary = 0.0;
                          else
                          assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
                          nextBoundary = max;


                          double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);

                          if (maximumDistanceToTravelInCurrentDirection <= remainingDistance)
                          currentPosition = nextBoundary;
                          remainingDistance -= maximumDistanceToTravelInCurrentDirection;
                          currentVelocity *= -1;
                          else
                          currentPosition += remainingDistance * Math.signum(currentVelocity);
                          remainingDistance = 0;



                          return new doublecurrentPosition, currentVelocity;



                          Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.



                          The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.



                          Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position lies within the permitted range), but also handling special cases like the infinities or Double.NaN. E.g., if you check whether position >= 0 && position <= max, then you automatically have NaN covered for position and max, because the comparison operators and the equality operator == always return false if one operand is NaN (even Double.NaN == Double.NaN returns false, which is why there's a method Double.isNaN(double)), but position might still be Double.POSITIVE_INFINITY if max is also Double.POSITIVE_INFINITY. Also, max should probably be greater than 0 (which would not be covered by the aforementioned condition either).






                          share|improve this answer















                          I assume "next" in getNextPositionAndVelocity means "after one unit of whatever temporal unit you use in the unit of the velocity", since the change of a position based on a velocity only makes sense in the context of a time span.



                          As for your code, you could simply model the path of the object by breaking it up into subpaths where the direction does not change, like this:



                          public double getNextPositionAndVelocity(double position, double velocity, double max) 
                          double remainingDistance = Math.abs(velocity);
                          double currentVelocity = velocity;
                          double currentPosition = position;

                          while (remainingDistance > 0.0)
                          double nextBoundary;
                          if (currentVelocity < 0.0)
                          nextBoundary = 0.0;
                          else
                          assert currentVelocity > 0.0; //cannot be 0 or NaN, not if we're in the loop
                          nextBoundary = max;


                          double maximumDistanceToTravelInCurrentDirection = Math.abs(nextBoundary - currentPosition);

                          if (maximumDistanceToTravelInCurrentDirection <= remainingDistance)
                          currentPosition = nextBoundary;
                          remainingDistance -= maximumDistanceToTravelInCurrentDirection;
                          currentVelocity *= -1;
                          else
                          currentPosition += remainingDistance * Math.signum(currentVelocity);
                          remainingDistance = 0;



                          return new doublecurrentPosition, currentVelocity;



                          Admittedly, this is more code than your version, but then, you don't consider the possibility that the range is smaller than the velocity, and if this is the case, an object might bounce off an edge more than once.



                          The above code could be optimized by first calculating the velocity modulo twice the range, because after two range lenghts, the position and velocity of the object will be identical to its initial position and velocity.



                          Also, you should validate the arguments. This not only entails checking whether the arguments are valid with respect to each other (e.g. whether position lies within the permitted range), but also handling special cases like the infinities or Double.NaN. E.g., if you check whether position >= 0 && position <= max, then you automatically have NaN covered for position and max, because the comparison operators and the equality operator == always return false if one operand is NaN (even Double.NaN == Double.NaN returns false, which is why there's a method Double.isNaN(double)), but position might still be Double.POSITIVE_INFINITY if max is also Double.POSITIVE_INFINITY. Also, max should probably be greater than 0 (which would not be covered by the aforementioned condition either).







                          share|improve this answer













                          share|improve this answer



                          share|improve this answer











                          answered Apr 28 at 23:13









                          Stingy

                          1,888212




                          1,888212






















                               

                              draft saved


                              draft discarded


























                               


                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193165%2fcalculate-next-position-and-velocity-after-bounce%23new-answer', 'question_page');

                              );

                              Post as a guest













































































                              Popular posts from this blog

                              Chat program with C++ and SFML

                              Function to Return a JSON Like Objects Using VBA Collections and Arrays

                              Will my employers contract hold up in court?