Relatives and global positioning

If we don’t use scaling, it works well but there…
it doesn’t work at all… and I really don’t find why.

If you know it…

thank you VERY much in advance !!!

The sketch is here !

Otherwise, Openprocessing indicates an error that I don’t have at all on my computer when I run this sketch!

N.B. same sketch in Processing :

transform_java

Hi! I think I can see two problems in runOutMatrix:

  • I think you aren’t accumulating the parent’s position, only its scale. The child’s total position should be createVector(parentX + parentScale * childX, parentY + parentScale + childY), as the parent’s scale also applies to the position relative to the parent.
  • It looks like you’re only accumulating position/scale from the direct parent, but that parent may also have a parent. Likely you will need to make your function recursive to account for that.
3 Likes

Also one thing that might be of interest is the DOMMatrixReadOnly JavaScript class: DOMMatrixReadOnly It lets you keep track of a transform with multiple nested translations and scales and will also let you extend your code to include rotations too if you need.

It would let you do something like this:

class Thing {
  globalTransform() {
    let parentMatrix = new DOMMatrixReadOnly()
    if (this.parent) {
      parentMatrix = this.parent.globalTransform()
    }
    return parentMatrix
      .translate(this.position.x, this.position.y)
      .scale(this.scale)
  }

  runOutMatrix() {
    push()
    const m = this.globalMatrix()
    applyMatrix(m.a, m.b, m.c, m.d, m.e, m.f)
    // draw something here
    pop()

    for (const child of this.children) {
      child.runOutMatrix()
    }
  }
4 Likes

THANK you beaucoup… (a lot) :upside_down_face:

It looks super interesting !!!

Yes indeed, taking care of the rotation is my next goal :hatching_chick: !

I will watch this very closely as soon as possible (I can’t wait!)… I have to take care of something else by Saturday evening - Sunday! :sad_but_relieved_face:

your webpage https://www.davepagurek.com/ seems very interesting too (:cry: I’m going to come back to it later !)

1 Like

Hello @EricRogerGarcia,

I did some more digging:

There may be something in there that can help with p5.js!

:)

Related:

1 Like

There, it works!

(I didn’t have much time….)
(In Processing because I prefer Java for thinking!)

I will take care of the rotation issue now.

N.B. I absolutely need to solve this because the upcoming collision management will have to be done outside of the transformations applied to the objects for their display

P.S. I will also look at everything you told me about to learn new things!

thanks a lot ! :grin:

Thing things;

void setup() {
  size(1000, 600);
  things=new Thing(width/2, height/2, 0.001);
  for (int i=0; i<10; i++) {
    Thing newThing=new Thing(random(width)-width/2, random(height)-height/2, random(1, 4));
    things.addChild(newThing);
    for (int j=0; j<5; j++) {
      newThing.addChild(new Thing(random(width/2)-width/4, random(height/2)-height/4, random(1,4)));
    }
  }
  frameRate(20);
}

void draw() {
  background(200);
  things.run();
  things.scale += .003;
}

class Thing {
  PVector position, globalPosition;
  float scale, globalScale;
  Thing parent;
  ArrayList<Thing> children;

  Thing(float x, float y, float scale) {
    this.position=new PVector(x, y);
    this.globalPosition=this.position.copy();  // globalPosition : Vector
    this.scale=scale; // scale : Number
    this.globalScale=scale;
    parent=null; // parent : Thing
    children = new ArrayList<>(); // children : Array<Thing>
  }

  void addChild(Thing child) {  // child : Thing
    this.children.add(child);
    child.parent = this;
  }

  void runInMatrix() {
    push();
    translate(this.position.x, this.position.y); // translate first so position / parent coordinate system
    scale(this.scale); // scale then: display in the scale of the parent * scale of the object

    // display
    if (parent==null) {
      fill(0, 0, 0);
    } else {
      fill(255, 0, 0); // red
    }
    circle(0, 0, 20);
    
    for (Thing child : this.children) {
      child.runInMatrix();
    }

    pop();
  }

  void runOutMatrix() {
    if (this.parent!=null) { // not the root Thing
      this.globalScale = this.parent.globalScale * this.scale; // to show the object
      this.globalPosition=this.parent.globalPosition.copy().add(position.copy().mult(parent.globalScale));
    } else {
      globalScale=scale;
    }

    //display
    fill(0, 255, 0); // green
    circle(this.globalPosition.x, this.globalPosition.y, 10*globalScale);

    for (Thing child : this.children) {
      child.runOutMatrix();
    }
  }

  void run() {
    this.runInMatrix();
    this.runOutMatrix();
  }
}

et voilà !!!

Thing things;

void setup() {
  size(1000, 600);
  things=new Thing(width/2, height/2, 40, 40, 0.6, 2)
      .setRotationVelocity(0.01);
  for (int i=0; i<10; i++) {
    Thing newThing=new Thing(random(width)-width/2, random(height)-height/2, 40, 40, random(0, 2), random(1, 7))
      .setRotationVelocity(0.02);
    things.addChild(newThing);
    for (int j=0; j<5; j++) {
      newThing.addChild(new Thing(random(width/2)-width/4, random(height/2)-height/4, 40, 40, random(0, 2), random(1, 4)));
    }
  }
  frameRate(20);
  rectMode(CENTER);
}

void draw() {
  background(200);
  things.run();
}

class Thing {
  PVector position, globalPosition;
  float scale, globalScale;
  Thing parent;
  ArrayList<Thing> children;
  float twidth, theight, rotation;
  float globalRotation;
  float rotationVelocity=0;

  Thing(float x, float y, float w, float h, float scale, float r) {
    this.position=new PVector(x, y);
    this.globalPosition=this.position;  // globalPosition : Vector
    this.scale=scale; // scale : Number
    this.globalScale=scale;
    parent=null; // parent : Thing
    children = new ArrayList<>(); // children : Array<Thing>
    twidth = w;
    theight = h;
    rotation=r;
  }

  Thing setRotationVelocity(float rv) {
    rotationVelocity=rv;
    return this;
  }

  void runRotation() {
    rotation+=rotationVelocity;
    for (Thing child : this.children) {
      child.runRotation();
    }
  }

  void addChild(Thing child) {  // child : Thing
    this.children.add(child);
    child.parent = this;
  }

  void runInMatrix() {
    push();
    translate(this.position.x, this.position.y); // translate first so position / parent coordinate system
    scale(this.scale); // scale then: display in the scale of the parent * scale of the object
    rotate(rotation);

    // display
    if (parent==null) {
      fill(0, 0, 0);
    } else {
      fill(255, 0, 0); // red
    }
    rect(0, 0, twidth, theight);

    for (Thing child : this.children) {
      child.runInMatrix();
    }

    pop();
  }

  void runOutMatrix() {
    if (this.parent!=null) { // not the root Thing
      this.globalScale = this.parent.globalScale * this.scale; // to show the object
      globalRotation=parent.globalRotation + this.rotation;
      PVector positionWithScale = position.copy().mult(parent.globalScale);
      globalPosition=parent.globalPosition.copy().add(positionWithScale.setHeading(position.heading()+parent.globalRotation));
    } else { // root Thing
      globalScale=scale;
      globalRotation=rotation;
    }


    //display
    fill(0, 255, 0); // green
    resetMatrix();
    translate(globalPosition.x, globalPosition.y);
    rotate(globalRotation);
    rect(0, 0, twidth*globalScale/2, theight*globalScale/2);

    for (Thing child : this.children) {
      child.runOutMatrix();
    }
  }

  void run() {
    runRotation();
    this.runInMatrix();
    this.runOutMatrix();
  }
}

See here in P5js