ANAR+ Transformations

ANAR+ makes use of linear transformations such as rotations, translations and scaling. It is possible to declare them as variables or to call a function on a geometrical element to transform it. Here a rotation of 90 degrees around the Z axis on a Face object.

Face f;
 
f.rotateZ(PI/2);

The advantage of declaring a transformation as variable is that it is possible to reuse it on several geometrical elements.

Face f,g;
 
Transform t = new Transform();
t.rotateZ(PI/2);
...
f.apply(t);
g.apply(t);

If you modify the transformation after applying it to some element, the change will be propagated to the elements the transformation has been applied to.

Face f;
 
Transform t = new Transform();
t.rotateZ(PI/2);
...
f.apply(t);
...
t.rotateY(PI/2);

Such transformation can be chained.

Face f;
f.rotateZ(PI/2).scale(2).translate(100,-10,30);
Transform t = new Transform();
t.rotateZ(PI/2).scale(2).translate(100,-10,30);

Of course one can use parametric elements with transformations.

Param s = new Param(2);
Pt p = Anar.Pt(1,10,23);
 
Transform t = new Transform();
 
t.rotateZ(PI/2).scale(s).translate(p);

Transformations on an Object

import anar.*;
import processing.opengl.*;
 
Obj myObj = new Obj();
 
public void setup(){
  size(800,400,OPENGL);
  Anar.init(this);
  Anar.drawAxis(true);
  initForm();
}
 
void initForm(){
 
  //Create a new set of Transformations
  Transform myTransform = new Transform();
  myTransform.translate(20,0,0);
  myTransform.rotateZ(.5f);
  myTransform.scale(1,1.09f,1.05f);
 
  //Create a box
  Obj box = new Box(20,20,10);
 
  for(int i=0; i<30; i++)
  {
    Obj myCopy = box.copy();  //Create an obj from box
    myCopy.apply(myTransform);  //Apply the set of transformations to the copy
    myObj.add(myCopy);          //Add myCopy obj to my main obj myObj
    box = myCopy;               //Swap box <--> myCopy
    //    myCopy is now the base for the next loop
  }
 
  Anar.camTarget(myObj);
 
  //Get the sliders from the set of transform
  //    Note: here, we don't use an obj to create the sliders.
  Anar.sliders(myTransform);
}
 
public void draw(){
  background(155);
  myObj.draw();
}

anar.ch_img_studio.01_00573.jpg

Random Box Array

Another example with a 2-dimensional set of modules with random variations.

import anar.*;
import processing.opengl.*;
 
Obj myObj;
 
void setup() {
  size(800, 400, OPENGL);
  Anar.init(this);
  initForm();
}
 
//Create parameter array to store individual height values
Sliders myParams = new Sliders();
 
int edge = 10; 
 
int Nx = 17;
int Ny = 6;
 
 
void initForm() {
  //Create a new Object to store our shape
  myObj = new Obj();  
 
  Obj module;
 
 
  for (int i=0; i<Nx; i++) {
    for (int j=0; j<Ny; j++) {
      Param p = new Param(random(20));
      Transform t = new Transform();
      t.translate(edge*i,0,0);
      t.translate(0,0,edge*j);
 
      module = new Box(edge,edge,1).translate(-edge/2,-edge/2).rotateX(PI/2).rotateZ(p);
 
      //Add the copy to myObj
      myObj.add(module.apply(t));
 
      //Create sliders for the parameter array
      myParams.add(p);
    }
  }
  Anar.camTarget(myObj);
}
 
void draw() {
  background(150);
  myObj.draw();
  //  myParams.draw();
}

anar.ch_img_studio.01_facadearray.jpg

Frame of reference

As seen already in the previous examples, parameters can be used for defining 3-dimensional linear transformations such as translations, scaling, rotations, etc. By default, the action of these transformations is centered at the origin, which means that a scaling of 2 will double the distance of a point to the origin.

As a result a scale transformation with different scaling values on every axis will distort the scaled element if it is not aligned with the axis. Here is an example.

import anar.*;
import processing.opengl.*;
 
Obj box;
 
void setup() {
  size(800, 400, OPENGL);
  Anar.init(this);
  Anar.drawAxis();
 
  Param p1 = new Param(1,0,10).addToSlidersMain();
  Param p2 = new Param(2,0,10).addToSlidersMain();
  Param p3 = new Param(3,0,10).addToSlidersMain();
 
  box = new Box(30,20,10);
  box.rotateX(0.2);
  box.rotateY(0.3);
  box.rotateZ(0.4);
  box.scale(p1,p2,p3);
 
}
 
void draw() {
  background(150);
  box.draw();
}

Another example of the origin problem can be found in the Random Box Array code example. Note the difference when removing the translation(-edge/2,-edge/2) applied on the Box after its creation.

If this translation shows how to remedy a simple situation, one actually often needs a transformation centered and oriented with a local frame of reference. This is done in ANAR+ by specifying the local frame when initializing the transformation.

Pt p,q,r;
...
Transform t = new Transform(p,q,r);
t.rotateZ(PI/3);

In the code above the transformation

  • will be centered on p,
  • the XY plane will be identified with the pqr plane
  • the Y axis will be aligned with the direction pr (this is a bug right now and it will be changed soon to X axis aligned with pq)
  • the Z axis will be aligned with the pq x pr direction.

The subsequent rotation along the Z axis will thus correspond to a rotation on the pqr plane. Note that if pq and pr are not orthogonal to each other the X axis will not be aligned with direction pq, which means that one should use cautiously rotation around the X axis.

Solution

import anar.*;
import processing.opengl.*;
 
Obj box;
 
void setup() {
  size(800, 400, OPENGL);
  Anar.init(this);
  Anar.drawAxis();
 
  box = new Box(30,20,10);
  box.rotateX(0.2);
  box.rotateY(0.3);
  box.rotateZ(0.4);
 
  Face f = box.face(3).copy().orphaned();
 
  Param p1 = new Param(1,0,10).addToSlidersMain();
  Param p2 = new Param(2,0,10).addToSlidersMain();
  Param p3 = new Param(3,0,10).addToSlidersMain();
 
  Transform t = new Transform(f.pt(1),f.pt(0),f.pt(2));
  t.scale(p1,p2,p3);
 
  box.apply(t);
 
}
 
void draw() {
  background(150);
  box.draw();
}

Folding

Folding is represented as rotations in the frame of reference of the precedent piece. Since the transformation is applied on the original piece, one only uses the transformation transporting the origin to the frame of reference.

Transform t = new Transform(p,q,r).postTransform();

One can also extract the transformation that puts the frame of reference at the origin aligned with the principal axis

Transform t = new Transform(p,q,r).preTransform();
import processing.opengl.*;
import anar.*;
 
/*
 * Example for Anar library by Guillaume LaBelle + Julien Nembrini
 * http://anar.ch
 */
 
void setup(){
    size(800,400,OPENGL);
 
  Anar.init(this);
  Anar.drawAxis(true);
 
  initForm();
}
 
 
void initForm(){
 
  Anar.sliders.add(new Param(PI,PI,2*PI));
 
  Transform tx = new TranslateX(10);
  Transform ty = new TranslateY(10);
 
  Anar.sliders.add(tx,ty);
 
  Pt a = Anar.Pt(0,0,0);
  Pt b = Anar.Pt(a,tx);
  Pt c = Anar.Pt(b,tx).apply(ty);
  Pt d = Anar.Pt(a,tx).apply(ty);
  Pt e = Anar.Pt(a,ty);
 
  Face shape = new Face(a,b,c,d,e);
 
  shape.rotateY(Anar.sliders.get(0));
  shape.fill(255,0,0);
 
  Anar.add(shape);
 
  Face f = shape;
 
  for (int i = 0; i<25; i++)
    Anar.add(f = new Face(Anar.face(0),new Transform(f.pt(3),f.pt(1),f.pt(2)).postTransform()).fill(255,255,0));
 
  for (int i = 0; i<15; i++)
    Anar.add(new Obj(Anar.objEnd()).apply(tx).apply(tx).apply(ty));
 
}
 
void draw(){
  background(155);
 
  Anar.draw();
  if(frameCount%100==0)
  Anar.camTarget(Anar.main);
}

example page