Constructor to create a new class instance by assignment

I was hoping I could create a new class instance by assignment like this:
innerRect = new Rect(outside.insetBy(m2, m2));

Is there any way to let a class have an constructor that can take an instance of the same type?

Or do I have to say something like this:

PVector newOrigin = outerRect.insetBy(m2, m2).origin;
PVector newSize = outerRect.insetBy(m2, m2).sz;
innerRect = new Rect(newOrigin, newSize);
Rect outerRect, innerRect; 
float m1 = 20;
float m2 = 5;

void setup() {
   size(414, 600);

   outerRect = new Rect(m1, m1, width - m1 * 2, height - m1 * 2);
   innerRect = new Rect(outerRect.insetBy(m2, m2));
}

void draw() {
   background(127);
}

class Rect {

   PVector origin;
   PVector sz;

   Rect() {
      origin = new PVector();
      sz = new PVector();
   }

   Rect(PVector origin, PVector sz) {
      this.origin = origin;
      this.sz = sz;
   }

   Rect(float x, float y, float w, float h) {
      origin = new PVector(x, y);
      sz = new PVector(w, h);
   }

   Rect(Rect r) {
      return new Rect(r.origin, r.sz);
   }

   Rect insetBy(float dx, float dy) {
      PVector newSize = new PVector(this.w() - dx, this.h() - dy);
      PVector newOrigin = PVector.add(this.origin, center()).sub(PVector.div(newSize, 2)); // this.origin + center() - (newSize / 2)
      return new Rect(newOrigin, newSize);
   }

   PVector center() {
      return new PVector(midX(), midY());
   }

   float w() {
      return sz.x;
   }

   float h() {
      return sz.y;
   }

   float midX() {
      return origin.x + sz.x / 2;
   }

   float midY() {
      return origin.y + sz.y / 2;
   }
}
1 Like

here is a working Sketch

please don’t say initializer but constructor

see https://www.processing.org/tutorials/objects/

Chrisir

Full Sketch I

Rect outerRect, innerRect; 
int m1 = 20;
int m2 = 5;

void setup() {
  size(1414, 900);

  outerRect = new Rect( new PVector(m1, m2), new PVector(width - m1 * 2, height - m1 * 2));
  innerRect =  outerRect.copy() ;

  innerRect.origin.x=57;
  innerRect.origin.y=53;
}

void draw() {
  background(0);

  fill(0, 0, 255);
  outerRect.display();
  fill(255, 0, 255);
  innerRect.display();
}

// ===============================================================

class Rect {

  PVector origin; // pos 
  PVector sz;     // size 

  // constr I
  Rect() {
    origin = new PVector();
    sz = new PVector();
  }

  // constr II
  Rect(PVector origin, PVector sz) {
    this.origin = origin.copy();
    this.sz = sz.copy();
  }

  // NOT a constr !!!!!!!!!!!!!!!!!
  Rect getMySelf (Rect r) {
    return 
      new Rect(r.origin, r.sz);
  }

  // NOT a constr !!!!!!!!!!!!!!!!!
  Rect copy() {
    return 
      new Rect(origin, sz);
  }

  // NOT a constr !!!!!!!!!!!!!!!!!
  void display() {
    rect(origin.x, origin.y, 
      sz.x, sz.y);
  }
  //
}//class
1 Like

Yes.

This would take a rect as a parameter to instantiate a new Rect object.

see constr III

Chrisir

Full Sketch II

Rect outerRect, innerRect; 
int m1 = 20;
int m2 = 5;

void setup() {
  size(1414, 900);

  outerRect = new Rect( new PVector(m1, m2), new PVector(width - m1 * 2, height - m1 * 2));
  innerRect = new Rect( outerRect );

  //innerRect.origin.x=57;
  //innerRect.origin.y=53;
}

void draw() {
  background(0);

  fill(0, 0, 255);
  // outerRect.display();
  fill(255, 0, 255);
  innerRect.display();
}

// ===============================================================

class Rect {

  PVector origin; // pos 
  PVector sz;     // size 

  // constr I
  Rect() {
    origin = new PVector();
    sz = new PVector();
  }

  // constr II
  Rect(PVector origin, PVector sz) {
    this.origin = origin.copy();
    this.sz = sz.copy();
  }

  // constr III
  Rect( Rect oldOne) {
    this.origin = oldOne.origin.copy();
    this.sz = oldOne.sz.copy();
  }

  // ---------------------------------------------------------------------------

  // NOT a constr !!!!!!!!!!!!!!!!!
  Rect getMySelf (Rect r) {
    return 
      new Rect(r.origin, r.sz);
  }

  // NOT a constr !!!!!!!!!!!!!!!!!
  Rect copy() {
    return 
      new Rect(origin, sz);
  }

  // NOT a constr !!!!!!!!!!!!!!!!!
  void display() {
    rect(origin.x, origin.y, 
      sz.x, sz.y);
  }
  //
}//class
2 Likes

Sorry, I understood now what you mean.

Since your method insetBy returns a new Rect (the new is inside the method), just call it like this:
innerRect = outerRect.insetBy(m2, m2);

Chrisir

Full Sketch III

Rect outerRect, innerRect; 
float m1 = 20;
float m2 = 5;

void setup() {
  size(414, 600);

  outerRect = new Rect(m1, m1, width - m1 * 2, height - m1 * 2);
  innerRect = outerRect.insetBy(m2, m2);
}

void draw() {
  background(127);

  fill(0, 0, 255);
  outerRect.display();
  fill(255, 0, 255);
  innerRect.display();
}

// ==========================================================================================

class Rect {

  PVector origin;
  PVector sz;

  Rect() {
    origin = new PVector();
    sz = new PVector();
  }

  Rect(PVector origin, PVector sz) {
    this.origin = origin;
    this.sz = sz;
  }

  Rect(float x, float y, float w, float h) {
    origin = new PVector(x, y);
    sz = new PVector(w, h);
  }

  // Rect(Rect r) {
  // return new Rect(r.origin, r.sz);
  // }

  Rect insetBy(float dx, float dy) {
    PVector newSize = new PVector(this.w() - dx, this.h() - dy);
    PVector newOrigin = PVector.add(this.origin, center()).sub(PVector.div(newSize, 2)); // this.origin + center() - (newSize / 2)
    return new Rect(newOrigin, newSize);
  }

  PVector center() {
    return new PVector(midX(), midY());
  }

  float w() {
    return sz.x;
  }

  float h() {
    return sz.y;
  }

  float midX() {
    return origin.x + sz.x / 2;
  }

  float midY() {
    return origin.y + sz.y / 2;
  }

  // NOT a constr !!!!!!!!!!!!!!!!!
  void display() {
    rect(origin.x, origin.y, 
      sz.x, sz.y);
  }
}
2 Likes

That makes sense, thank you.

Another question, why isn’t the new rectangle actually inset on the right and bottom? It’s supposed to be uniformly smaller and still centered within the original rectangle.

rect works with upper left corner

Look at rectMode()

1 Like

You can have one ctor use another one like this

   Rect(Rect r) {
      this(r.origin, r.sz);
   }

which would call this method

You need to change the first line
this.origin = origin; // Does not copy PVector, the rects will share the PVector
to
this.origin = origin.copy();

copy() is a method in PVector that creates a new PVector based on the original

3 Likes

Sorry, I should not have been adding the origin here:

PVector newOrigin = PVector.add(this.origin, center()).sub(PVector.div(newSize, 2)); // this.origin + center() - (newSize / 2)

This works as expected:

PVector newOrigin = PVector.sub(center(), (PVector.div(newSize, 2))); // center() - (newSize / 2)

Thanks everyone

Here is the whole thing which now works the way I wanted.

Rect outerRect, innerRect; 
float m1 = 20;
float m2 = 100;

void setup() {
   size(414, 600);

   outerRect = new Rect(m1, m1, width - m1 * 2, height - m1 * 2);
   
   // either of these now work to construct a new Rect and assign it to innerRect
   //innerRect = new Rect(outerRect.insetBy(m2, m2));
   innerRect = outerRect.insetBy(m2, m2);
}

void draw() {
   background(127);
   
   fill(0, 0, 255);
   outerRect.display();

   fill(255, 0, 255);
   innerRect.display();
}

// ==========================================================================================

class Rect {

   PVector origin;
   PVector sz;

   Rect() {
      origin = new PVector();
      sz = new PVector();
   }

   Rect(Rect r) {
      this(r.origin, r.sz);
   }

   Rect(PVector origin, PVector sz) {
      // this.origin = origin; //  this is wrong - Does not copy PVector, the rects will share the PVector
      this.origin = origin.copy();
      this.sz = sz.copy();
   }

   Rect(float x, float y, float w, float h) {
      origin = new PVector(x, y);
      sz = new PVector(w, h);
   }

   Rect insetBy(float dx, float dy) {
      PVector newSize = new PVector(this.w() - dx * 2, this.h() - dy * 2);

      PVector newOrigin = PVector.sub(center(), PVector.div(newSize, 2)); // center() - (newSize / 2)

      return new Rect(newOrigin, newSize);
   }

   PVector center() {
      return new PVector(midX(), midY());
   }

   float w() {
      return sz.x;
   }

   float h() {
      return sz.y;
   }

   float midX() {
      return origin.x + sz.x / 2;
   }

   float midY() {
      return origin.y + sz.y / 2;
   }

   float maxX() {
      return origin.x + sz.x;
   }

   float maxY() {
      return origin.y + sz.y;
   }

   // NOT a constr !!!!!!!!!!!!!!!!!
   void display() {
      rect(origin.x, origin.y, 
         sz.x, sz.y);
   }
}
1 Like

As I said you should use rectMode(CENTER); or not?

Also, since insetBy() returns a new rect this line

 innerRect = new Rect(outerRect.insetBy(m2, m2));

can be

 innerRect = outerRect.insetBy(m2, m2);

The plan was to use the default rectMode(CORNER);

I see it is better to do it this way in this case.

1 Like

Not sure if this is needed

I guess not. I can’t think of any reason to have this.

here is my version with only one constructor

Chrisir


Rect outerRect, innerRect; 

void setup() {
  size(414, 600);

  float m1 = 20;
  float m2 = 100;

  outerRect = new Rect(
    new PVector(m1, m1), 
    new PVector(width - m1 * 2, height - m1 * 2));

  // either of these now work to construct a new Rect and assign it to innerRect
  //innerRect = new Rect(outerRect.insetBy(m2, m2));
  innerRect = outerRect.insetBy(m2, m2);
}//func 

void draw() {
  background(127);

  fill(0, 0, 255);
  outerRect.display();

  fill(255, 0, 255);
  innerRect.display();
}//func 

// ==========================================================================================

class Rect {

  PVector origin = new PVector();
  PVector sz     = new PVector();

  Rect(PVector origin_, PVector sz_) {
    // this.origin = origin_; //  this is wrong - Does not copy PVector, the rects will share the PVector
    origin = origin_.copy();
    sz = sz_.copy();
  } // constr 

  // ------------------------------------------------
  // methods of the class 

  Rect insetBy(float dx, float dy) {
    PVector newSize = new PVector(w() - dx * 2, h() - dy * 2);
    PVector newOrigin = PVector.sub(center(), PVector.div(newSize, 2)); 
    return new Rect(newOrigin, newSize);
  } // method 

  PVector center() {
    return new PVector(midX(), midY());
  }

  float w() {
    return sz.x;
  }

  float h() {
    return sz.y;
  }

  float midX() {
    return origin.x + w() / 2;
  }

  float midY() {
    return origin.y + h() / 2;
  }

  float maxX() {
    return origin.x + w();
  }

  float maxY() {
    return origin.y + h();
  }

  void display() {
    rect(origin.x, origin.y, 
      sz.x, sz.y);
  }
}//class
//
1 Like

These lines no longer apply, you might want to take them out of your example.

This is nice to have if you are pretending to make a CGRect :grinning:

1 Like

Yes

But it’s the same like with two PVectors

It is, but if you’re trying to use Processing to work out ideas for programming iOS, this one gets a lot more use generally. There is no Daniel Shiffman in the world of iOS programming telling everyone how nice it is to use Vectors instead of x, y. So all the drawing code is doubled, no one uses Vectors. If you want to use vector math at all, you have to write your own extensions. It’s bleak.

1 Like