[SOLVED] Help Updating G4P GUI Mandelbrot Code to Processing 3x

In an attempt to better understand Qscript Math in relation to what I’m already familiar with and help develop the other programs I’m working on I found this legacy source code from quarks openprocessing page. I realize that it’s written for processing 1x or 2x and was wondering if I could get some help updating it to run in processing 3x, seeing as I’m totally unfamiliar with the G4P GUI and most all the errors seem to be GUI related.

/**
 * The most complicated example so far. This will display the Mandelbrot
 * set in a separate window. Draw a rectangle over the image to create 
 * a new Mandelbrot in a new window ...
 *
 * by Peter Lager
 */
 
import g4p_controls.*;

//Believe this is the Previous G4P GUI Library
//import guicomponents.*;

final int MAX_ITERATE = 128;

final int MAX_WIDTH = 300;
final int MAX_HEIGHT = 300;

final int MIN_WIDTH = 30;
final int MIN_HEIGHT = 30;

int[] colors = new int[MAX_ITERATE];

GButton btnStart;

int locX = 100, locY = 100;
ArrayList windows = new ArrayList();

String t0,t1,t2;


class Complex {

  public double real;
  public double img;

  Complex(){
    real = img = 0.0f;
  }

  /**
   *      * @param r
   *      * @param i
        */
  public Complex(float r, float i) {
    super();
    this.real = r;
    this.img = i;
  }

  public void set(double colX, double rowY){
    real = colX;
    img = rowY;
  }

  public Complex add(Complex c){
    real += c.real;
    img += c.img;
    return this;
  }

  public void mult(Complex c){
    double nReal = real * c.real - img * c.img;
    double nImg = real * c.img + img * c.real;
    real = nReal;
    img = nImg;
  }

  public Complex squared(){
    double nReal = (real - img)*(real + img);
    double nImg = 2 * real * img;
    real = nReal;
    img = nImg;  
    return this;
  }

  public double sizeSquared(){
    return real * real + img * img;
  }
}

/**
 * Simple class that extends GWinData and holds the data that is specific
 * to a particular window.
 */
class MyWinData extends GWinData {

  public int msx,msy,mex,mey;
  public double sx,sy,ex,ey;
  public int w, h;
  public PImage img;
  public boolean imgDone;
}

void setup(){
  size(300,200);
  G4P.setFont(this, "Serif", 14);
  G4P.setColorScheme(this, GCScheme.RED_SCHEME);
  btnStart = new GButton(this, "START", (width - 80)/2,height - 30,80,20);
  t0 = "MANDELBROT GALORE\n";
  t1 = "Click on the START button to see the Mandelbrot set in a separate window. ";
  t2 = " To zoom into the set drag a box on the area you are interested in and ";
  t2 += "he enlarged image will appear in a new window.";

  createColours();
}

public void createColours(){
  colors[MAX_ITERATE-1] = color(0);
  float hue = 0.0f;
  float bright = 1.0f;
  float binc = 0.009f/MAX_ITERATE;
  for(int i = 0; i < MAX_ITERATE - 2; i++){
    colors[i] = Color.HSBtoRGB(hue, 1.0f, bright);
    hue = (hue + 0.1309f) % 1.0f ;
    bright -= binc;
  }
}

/**
 * Create a PImage of the correct size and using the data
 * for a window create the Mandelbrot image. Singnal when
 * complete by setting imgDone = true
 * 
 * @param data
 */
public void calcMandlebrot(MyWinData data){
  double x0,x1,y0,y1, deltaX, deltaY;
  double colX, rowY;
  x0 = data.sx;
  x1 = data.ex;
  y0 = data.sy;
  y1 = data.ey;
  deltaX = (x1 - x0)/data.w;
  deltaY = (y1 - y0)/data.h;
  data.img.loadPixels();
  int count = 0;
  Complex c = new Complex();
  Complex z = new Complex();

  colX = x0;
  rowY = y0;
  int minC = 999, maxC = -999;
  for(int row = 0; row < data.h; row++){
    colX = x0;
    for(int col = 0; col < data.w; col++){
      count = 0;
      c.set(colX, rowY);
      z.set(colX, rowY);
      while(count < MAX_ITERATE-1 && z.sizeSquared() < 4.0){
        z = z.squared().add(c); 
        count++;
      }
      if(count < minC) minC = count;
      if(count > maxC) maxC = count;
      data.img.pixels[col + row * data.w] = colors[count];
      colX += deltaX;
    }
    rowY += deltaY;
  }
  data.img.updatePixels();
  data.imgDone = true;
}

/**
 * Create and display a new Frame for a Mandelbrot
 * make it as big as possible to fit MAX_WIDTH and MAX_HEIGHT
 * but reject if this results in the width or height being less
 * than the minimum vales (MIN_WIDTH, MIN_HEIGHT.
 * 
 * @param nsx
 * @param nex
 * @param nsy
 * @param ney
 * @return
 */
public boolean makeNewBrotWindow(double nsx, double nex, double nsy, double ney){
  MyWinData mydata = new MyWinData();
  GWindow window = null;
  float ratio = (float) ((nex-nsx)/(ney-nsy));
  if(ratio > MAX_WIDTH/MAX_HEIGHT){
    mydata.w = MAX_WIDTH;
    mydata.h = (int)( MAX_HEIGHT / ratio);
  }
  else {
    mydata.h = MAX_HEIGHT;
    mydata.w = (int)( MAX_WIDTH * ratio);
  }
  mydata.sx = nsx;
  mydata.sy = nsy;
  mydata.ex = nex;
  mydata.ey = ney;
  mydata.imgDone = false;

  if(mydata.w >= MIN_WIDTH && mydata.h >= MIN_HEIGHT){
    mydata.img = new PImage(mydata.w, mydata.h);
    window = new GWindow(this,"Main", locX, locY, mydata.w, mydata.h, false, null);
    windows.add(window);
    locX = (locX + mydata.w + 20)%(screen.width - MAX_WIDTH);
    locY = (locY + 20)%(screen.height - MAX_HEIGHT);
    window.addData(mydata);
    window.addDrawHandler(this, "windowDraw");
    window.addMouseHandler(this, "windowMouse");
    calcMandlebrot(mydata);
    return true;
  }
  return false;
}


/**
 * Click the button to create the windows.
 * @param button
 */
public void handleButtonEvents(GButton button){
  if(btnStart == button){
    makeNewBrotWindow(-2.0f,0.5f,-1.25f,1.25f);
    btnStart.setVisible(false);
  }
}

/**
 * Draw for the main window
 */
void draw(){
  background(0,192,0);
  textAlign(CENTER);
  if(windows.isEmpty())
    text(t0+t1+t2,10,10,width - 20,height - 40);
  else {
    text(t0+t2,10,10,width - 20,height - 40);
    noLoop();
  }
}

/**
 * Handles mouse events for ALL GWindow objects
 * 
 * @param appc the PApplet object embeded into the frame
 * @param data the data for the GWindow being used
 * @param event the mouse event
 */
public void windowMouse(GWinApplet appc, GWinData data, MouseEvent event){
  MyWinData d = (MyWinData)data;
  if(d.imgDone == false)
    return;
  switch(event.getID()){
  case MouseEvent.MOUSE_PRESSED:
    d.msx = d.mex = appc.mouseX;
    d.msy = d.mey = appc.mouseY;
    appc.loop();
    appc.frameRate(30);
    break;
  case MouseEvent.MOUSE_RELEASED:
    d.mex = appc.mouseX;
    d.mey = appc.mouseY;
    // Make sure the coordinates are top left / bottom left
    int temp;
    if(d.msx > d.mex){
      temp = d.msx; 
      d.msx = d.mex; 
      d.mex = temp;
    }
    if(d.msy > d.mey){
      temp = d.msy; 
      d.msy = d.mey; 
      d.mey = temp;
    }
    // Calculate the new Mandelbrot plane coordinates
    double nsx,nex,nsy,ney;
    nsx = dmap((double)d.msx, (double)0, (double)d.w, d.sx, d.ex);
    nex = dmap((double)d.mex, (double)0, (double)d.w, d.sx, d.ex);
    nsy = dmap((double)d.msy, (double)0, (double)d.h, d.sy, d.ey);
    ney = dmap((double)d.mey, (double)0, (double)d.h, d.sy, d.ey);
    makeNewBrotWindow(nsx, nex, nsy, ney);
    d.msx = d.mex = d.msy = d.mey = 0;
    appc.noLoop();
    break;
  case MouseEvent.MOUSE_DRAGGED:
    d.mex = appc.mouseX;
    d.mey = appc.mouseY;
    break;      
  }
}

/**
* Copied from PApplet and converted floats to doubles 
* @param value
* @param istart
* @param istop
* @param ostart
* @param ostop
* @return
*/
double dmap(double value, double istart, double istop, double ostart, double ostop) {
  return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
}

/**
 * Handles drawing to the windows PApplet area
 * 
 * @param appc the PApplet object embeded into the frame
 * @param data the data for the GWindow being used
 */
public void windowDraw(GWinApplet appc, GWinData data){
  MyWinData d = (MyWinData)data;
  if(d.imgDone){
    appc.image(d.img,0,0);
    if(d.msx != d.mex || d.msy != d.mey){
      appc.strokeWeight(2);
      appc.stroke(255);
      appc.noFill();
      appc.rectMode(CORNERS);
      appc.rect(d.msx,d.msy,d.mex,d.mey);
    }  
  }
}
1 Like

This example is included with the all versions of G4P so you can find it in the examples. Select File > Examples from the menus open Contributed Libraries > G4P > G4P_Mandelbrot.

Note this example does not use the QScript library it demonstrates using multiple windows.

You can find out more about G4P/multiple windows and QScript on my website Quark’s Place

2 Likes

I didn’t realize libraries came with their own examples. Ohh okay it uses it’s own class but not the QScript library. Thank you for letting me know!