improved class Coordinates – the code

//version of 23rd jan 2014
// relates technical pixelindizes (i,j) to geometric image coordinates (x,y) and inverse
// both (i,j) and (x,y) are Vector objects with float components
// (i,j) are float for pixel interpolation.
//
// Note: vertical coordinates are corrected, j=0 is at bottom, j=image.height is at top
//
//  use for the computer screen, input PImages of arbitrary size, 
//  output PImages or PGraphics of a multiple of the screen size.
//
//  note that transformations of coordinates often cause confusion and have to be defined carefully
//
// thisWidth,thisHeight: width and height of related PImage, PGraphics or screen
// unitLength: number of screen pixels per unit length of the image
// magnification: number of pixels of an output image per screen pixel; magnification=1 for the screen
//                (not valid for input images which have not the same image ratios as the screen)
//   thus the scale to go from image to pixels is unitLength*magnification
//
// angle: the image axis are rotated by this angle with respect to pixel axis, 
//     
// translation: Vector in pixels between origin of pixel coordinates and image coordinates
// Note: y-coordinates are corrected, so for translation=0 the origin of the image coordinates is at lower left corner
// imageToPixel: Scaleing and rotation to go from image to pixels
// pixelToImage: same, from pixels to image

class Coordinates{
  int thisWidth, thisHeight;
  float unitLength,magnification,angle;
  Vector translation,imageToPixel,pixelToImage;

  Coordinates(float mp){              // for screen use mp=1, for high resolution PImages and PGraphics mp>>1
    magnification=mp;
    unitLength=1;
    thisWidth=int(width*magnification);
    thisHeight=int(height*magnification);
    initUnits();
  }
  
  Coordinates(PImage image){           // use with input image, change scale if necessary
    magnification=1;                   // does not fit to the screen anyway
    unitLength=width/5;
    thisWidth=image.width;
    thisHeight=image.height;
    initUnits();
  }

  void initUnits(){
    translation=new Vector(thisWidth/2,thisHeight/2);
    imageToPixel=new Vector(1,0);
    pixelToImage=new Vector(1,0);
    angle=0;
    setTransformations();
  }
  
// set up the transformations (scale and rotation)
// depending on angle, unitLength and magnification

  void setTransformations(){
    float scale=unitLength*magnification;
    imageToPixel.set(scale*cos(angle),-scale*sin(angle));
    pixelToImage.set(cos(angle)/scale,sin(angle)/scale);
  }
  
  
//-----------------------------------------------------------------------
// changing coordinates of an image

//  set the unitLength and thus the scale

  void setUnitLength(float ul){
    unitLength=ul;
    setTransformations();
  }
  
//  change scale by given factor by changing the unitLength
  void multiplyScale(float factor){
    unitLength*=factor;
    setTransformations();
  }
  
//  change the rotation angle by given amount, rotates around image origin(0,0)
  void addAngle(float da){
    angle-=da;
    setTransformations();
  }
  
//  output image:
//  shift position of origin, as seen on screen, in terms of screen pixels 
//  shiftOrigin(-0.5*width/unitLength,-0.5*height/unitLength) puts origin at lower left corner
  void shiftOutputOrigin(Vector dt){
    translation.add(dt.mult(magnification));
  }
  
//  input image:
//  shift position of origin, as seen on screen, in terms of screen pixels 
//  shiftOrigin(-0.5*width/unitLength,-0.5*height/unitLength) puts origin at lower left corner
  void shiftInputOrigin(Vector dt){
    translation.sub(dt.mult(imageToPixel));
  }
  
  // copy transformation (scaling, rottation,translation) from another Coordinates object

  void copyTransformations(Coordinates original){
    unitLength=original.unitLength;
    angle=original.angle;
    translation=original.translation.copy().mult(magnification/original.magnification);
    setTransformations();
  }
  
  
//----------------------------------------------------------------------------------
// create fitting PImage or PGraphics
// format=RGB,ARGB or ALPHA. 
// Using RBG without transparency or ALPHA for black might reduce memory requirements and speed up things.

  PImage createPImage(int format){
    return createImage(thisWidth,thisHeight,format);
  }
  
  PImage createPImage(){                                                   //default RGB
    return createImage(thisWidth,thisHeight,RGB);
  }
  
  PGraphics createPGraphics(){
    return createGraphics(thisWidth,thisHeight);
  }
  
//---------------------------------------------------------------------------------
//  drawing on PGraphics: setting the transformations

void beginGraphics(PGraphics graphics){
    graphics.beginDraw();
    graphics.translate(translation.x,thisHeight-translation.y);
    graphics.scale(unitLength*magnification,-unitLength*magnification);
    graphics.rotate(-angle);
    trueStrokeWeight(1,graphics);
}
//  setting the stroke weight as number of pixels, independent of unitLength

void trueStrokeWeight(float w,PGraphics graphics){
   graphics.strokeWeight(w/unitLength); 
}

//  drawing on screen: setting the transformations

void beginGraphics(){
    translate(translation.x,thisHeight-translation.y);
    scale(unitLength*magnification,-unitLength*magnification);
    rotate(-angle);
    trueStrokeWeight(1);
}
//  setting the stroke weight as number of pixels, independent of unitLength

void trueStrokeWeight(float w){
   strokeWeight(w/unitLength); 
}

  //--------------------------------------------------------------------------------------
  //  calculate image coordinates from indizes to pixel, makes a new vector (x,y)
  //  the origin (0,0) is at (i,j)=(translation.x,translation.y)
    
  Vector getVector(float i,float j){
    Vector r=new Vector(i,thisHeight-j);    // correction of y-axis
    return r.sub(translation).mult(pixelToImage);
  }  
  
  //----------------------------------------------------------------------------
  //  calculate indizes(i,j) to pixels from image coordinates v=(x,y)
  
  Vector getPixel(Vector v){  
    Vector r=v.copy().mult(imageToPixel).add(translation);
    r.y=thisHeight-r.y;                        // correction of y-axis
    return r;
  }
}
This entry was posted in programming and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s