Multiplying vectors

Hi,

Everytime I want to do multiplications on PVectors I get frustrated as PVector.mult(PVector) doesn't exist. I've seen one or two threads on the forums about this, so I know that it apparently doesn't make much sense. Can someone point me to the correct way of multiplying a normalised position PVector with a pixel space PVector?

Say I have this:

PVector pixelSpaceSize = new PVector(400, 300); PVector normalizedPosition = new PVector(0.8, 0.2);

And I want to get the pixel space position of my normalised position? Ideally I'd do...

PVector pixelPosition = PVector.mult(pixelSpaceSize, normalizedPosition);

Right? But instead I now have to multiply the individual fields:

PVector pixelPosition = PVector.mult(pixelSpaceSize.x * normalizedPosition.x, pixelSpaceSize.y * normalizedPosition.y, pixelSpaceSize.z * normalizedPosition.z);

I'm sure there's a very good reason why this is not-done, but how should I approach this? Stick to the incredibly long x * x, y * y and z * z or is there some other method?

Many thanks

Tagged:

Answers

  • The only way is to create your own method that accepts 2 PVector s and returns a new PVector with the fields multiplied.

  • Thanks for your answer, but do you know why this isn't a standard function? Why can't I multiply/divide vectors with vectors out-of-the-box? I can remember reading that .mult() used to be able to multiply vectors with vectors in earlier versions of Processing, but got chopped as it wasn't mathematically correct. I'd rather have an answer from a maths point of view so I can write my code in a correct manner than have a work-around.

  • edited October 2016

    I'm sure there's a very good reason why this is not done, ...

    I can assure you there ain't at all!!! Just another ordinary case where we know better than the users. :O)
    Actually that overloaded method existed, for both mult() & div(), in the old Processing 1.5.1! \m/

    And it still exists in the Pjs library (JavaScript Mode). Just paste the code below at this link:
    http://ProcessingJS.org/tools/processing-helper.html

    PVector pixelSpaceSize = new PVector(400, 300);
    PVector normalizedPosition = new PVector(.8, .2);
    PVector pixelPosition = PVector.mult(pixelSpaceSize, normalizedPosition);
    println(pixelPosition);
    exit();
    

    You can download P5 v1.5.1 and check that out there too. 8-X
    And you can also compare the API references for both P5 & Pjs:

    1. https://Processing.org/reference/PVector_mult_.html
    2. http://ProcessingJS.org/reference/PVector_mult_/
  • I believe this previous post is relevant to the discussion:

    https://forum.processing.org/two/discussion/17482/multiply-two-pvectors

    Kf

  • edited October 2016

    @willemkempers -- I'm confused. When you say "multiply two vectors", and you don't mean PVector.mult() (which is a scalar), do you mean the dot product, or the cross product?

    As in PVector.cross()?

    PVector v1 = new PVector(10, 20, 2);
    PVector v2 = new PVector(60, 80, 6); 
    PVector v3 = v1.cross(v2);
    println(v3);  // Prints "[ -40.0, 60.0, -400.0 ]"
    

    Or do you mean something else?

    (And yes, it is weird that .mult isn't overloaded -- although I can see how that could get tricky / misleading given that other vector method overloading is about sources and targets).

  • edited October 2016

    It's very hard to convince Processing's devs to do what we wish for the project. [-O<

    For now, I've made a custom PVectorPlus class, in order to get back the lost functionality for both mult() & div() methods. :ar!

    You can paste that class in a separate tab, so it gets the job done and gets outta your sight! :-bd

    /**
     * PVectorPlus mult() & div() (v1.1)
     * GoToLoop (2016-Oct-16)
     * forum.Processing.org/two/discussion/18585/multiplying-vectors#Item_6
     */
    
    void setup() {
      PVector pixelSpaceSize = new PVector(400, 300);
      PVector normalizedPosition = new PVector(.8, .2);
      PVector pixelPosition = PVectorPlus.mult(pixelSpaceSize, normalizedPosition);
      println(pixelSpaceSize, normalizedPosition, pixelPosition);
      exit();
    }
    
    static class PVectorPlus extends PVector {
      PVectorPlus() {
      }
    
      PVectorPlus(float x, float y) {
        super(x, y);
      }
    
      PVectorPlus(float x, float y, float z) {
        super(x, y, z);
      }
    
      static PVector mult(PVector v1, PVector v2) {
        return mult(v1, v2, null);
      }
    
      static PVector mult(PVector v1, PVector v2, PVector t) {
        if (t != null)  t.set(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
        else t = new PVectorPlus(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
        return t;
      }
    
      PVectorPlus mult(PVector v) {
        x *= v.x;
        y *= v.y;
        z *= v.z;
        return this;
      }
    
      static PVector div(PVector v1, PVector v2) {
        return div(v1, v2, null);
      }
    
      static PVector div(PVector v1, PVector v2, PVector t) {
        if (t != null)  t.set(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z);
        else t = new PVectorPlus(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z);
        return t;
      }
    
      PVectorPlus div(PVector v) {
        x /= v.x;
        y /= v.y;
        z /= v.z;
        return this;
      }
    }
    
  • @GoToLoop AWESOMEEE

    @jeremydouglass: this is where my maths fail me. I'm not too familiar with getting dot and cross products, so I believed my maths to be off. Say I have a normalised position vector (not a translation, a position vector). I tend to normalise my positions as it's easier to scale stuff later on when drawing to pixel space. When I have to draw to pixel space however, I have to multiply two vectors together. The normalised position vector, and a total-screen-space vector. Could I use dot and cross product for that?

    @quark, in that topic @kfrajer mentioned, you said that "I suspect that they removed it because it has no mathematical meaning.", but how come? Why doesn't this have any mathematical meaning? And that will probably also answer... Why did it get chopped in later versions?

    Thanks

  • @willemkempers

    Other languages have refused to allow two-vector multiplication (such as Unity), instead requiring the programmer specify dot or cross. The grounds seems to be that vec*vec or vec.mult(vec) is ambiguous in ways that some people familiar with vector math may find immediately counter-intuitive.

    Maybe what you want is vector convolution, i.e. component-wise multiplication? In that case, a potential feature request might be to request PVector.convolute() be added. Although it looks like GoToLoop has solved your immediate problem, it might be nice to have a built-in....

  • it has no mathematical meaning

    Is it not a common operation. Matrix multiplication, dot product and cross product have a known meaning. Multiplying two vectors, I can't think of any meaning.

    multiplying a normalised position PVector with a pixel space PVector

    What are you trying to do there with that operation?

    Kf

  • edited October 2016

    @kfrajer -- willemkempers is doing scale-independent rendering.

    I tend to normalise my positions as it's easier to scale stuff later on when drawing to pixel space.

    So all object locations are stored in e.g. PVectors v1-v100 on a unit square. Then all their screen locations are derived at draw time by convolving / denormalizing / component-scaling each PVector with the same screen PVector(width,height) -- depending on whatever the target screen dimensions are.

    Edit: At least, I think that is what you meant. You mean each vector has components in the 0-1 range, right? Not that you are literally making every vector length=1 ( which is the normal vector 'normalize')?

  • @jeremydouglas thanks for all your links, I'll check them out in the morning! Cross product doesn't do what I want as it gives a vector perpendicular to the ones it gets, it doesn't scale on an independent x and y axis... I guess? Again: no experience with dot & cross.

    You've also got it correct on the 'why'. Say I have a grid object that I init with a size of 5x4, when normalising it, every node in the grid will be 0.2 apart from each other on the x-axis, and 0.25 on the y-axis. When later using this grid, i can scale it to whatever size and keep the same proportions.

  • edited October 2016

    Well, @GoToLoop 's PVectorPlus class method will do what you want!

    Or just use that method as a standalone mult function in any sketch, as per @quark:

    Edit: oops, typos! See correct version from @GoToLoop below:

  • edited October 2016

    Just a little correction: as stand-alone functions, implies there's no class PVectorPlus anymore!

    So at the else line, replace PVectorPlus w/ the original PVector: ;)
    else t = new PVector(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);

    Also, to indicate they don't depend on the PApplet sketch's instance, slap static on them: =P~

    void setup() {
      PVector pixelSpaceSize = new PVector(400, 300);
      PVector normalizedPosition = new PVector(.8, .2);
      PVector pixelPosition = mult(pixelSpaceSize, normalizedPosition);
      println(pixelSpaceSize, normalizedPosition, pixelPosition);
      exit();
    }
    
    static PVector mult(PVector v1, PVector v2) {
      return mult(v1, v2, null);
    }
    
    static PVector mult(PVector v1, PVector v2, PVector t) {
      if (t != null)  t.set(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
      else t = new PVector(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
      return t;
    }
    
  • @Jeremydouglass @willemkempers I would suggest to use @GoToLoop's full class. If one does multiplication, then one would also do division. They complement each other.

    In regards to the meaning of this type of multiplication, I think this concept comes from a transformation. In this case is going from different pixel space distribution, this transformation is not done between vectors but you would need a matrix. For this case, the matrix will be diagonal which would explain the result of the operation which has been simplified to a multiplication of the fields of the vectors against each other. Since processing does not have matrix operations (unless you import a specific library - "I am guessing they exist in the JAVA realm" ), you will be stuck with defining your own functions, as presented above.

    Kf

Sign In or Register to comment.