Help running a piece of code (ConvChainJava)

edited November 2017 in Library Questions

Hey guys , I am trying to run this: https://github.com/mxgmn/ConvChain

Which has a processing version over here: https://github.com/buckle2000/ConvChainJava

How am I supposed to set it up correctly? I cant quite get it to work, im getting some errors.

I am assuming I was to run main.java...

Thx! :)

Tagged:

Answers

  • Re:

    How am I supposed to set it up correctly?
    I cant quite get it to work, im getting some errors.

    How have you set it up currently?

    What specific error are you getting?

    • That ConvChain got some problems if you wish to compile it using the PDE. :-SS
    • 1st, it doesn't have a ".pde" file as an entry point for setup() & draw(). @-)
    • Then that "Main.java" needs to be converted to a proper "Main.pde".
    • 2nd, both "Generator.java" & "Pattern.java" are using lambdas. ~O)
    • However, the PDE doesn't accept lambda syntax yet, even for ".java" files! ~X(
    • Therefore, those lambdas need to be converted to their corresponding old style anonymous instantiations.
    • Which can be a challenging to find out the right way to do it for each lambda type. :-&
    • I can give it a try later. But I think I'm gonna have to fork that project for it. #:-S
  • it's a java project that uses the processing library, you need to compile it using ant or mvn or a makefile or an ide or something, none of which is provided (pet hate of mine)

    JAR=/path/to/processing-3.3/core/library/core.jar
    javac -cp ${JAR} ./src/ConvChain/Generator.java ./src/ConvChain/Pattern.java ./src/Main.java
    

    that's enough to get you the class files... i haven't got as far as running it...

  • (works in netbeans if you add the core.jar to the project)

    (still can't get it to run from the command line)

  • edited November 2017

    ok, quick port to non-java8 here:

    HOWEVER, the results look different from when i run it in netbeans so there might be a logical error somewhere. (original code left as comments)

    (you'll need the images from the original copied into data folder)

    //import ConvChain.Generator;
    //import processing.core.PApplet;
    //import processing.core.PImage;
    
    //public class Main extends PApplet {
    //    public static void main(String[] args) {
    //        PApplet.main(Main.class.getCanonicalName());
    //    }
    
    public void settings() {
      size(256, 128);
      noSmooth();
    }
    
    boolean[][] toArray(PImage image) {
      boolean[][] result = new boolean[image.width][image.height];
      for (int x = 0; x < image.width; ++x) {
        for (int y = 0; y < image.height; ++y) {
          int colour = image.pixels[y * image.width + x];
          if (colour == -16777216) {
            result[x][y] = false; // black
          } else {
            result[x][y] = true; // white
          }
        }
      }
      return result;
    }
    
    PImage toPImage(boolean[][] array, PImage result) {
      if (result == null) {
        result = createImage(array.length, array[0].length, RGB);
      }
    
      for (int x = 0; x < array.length; ++x) {
        for (int y = 0; y < array[0].length; ++y) {
          if (array[x][y]) {
            result.pixels[y * result.width + x] = color(1);
          } else {
            result.pixels[y * result.width + x] = color(0);
          }
        }
      }
      result.updatePixels();
      return result;
    }
    
    
    PImage image;
    Generator generator;
    PImage output;
    
    void updateOutput() {
      output = toPImage(generator.field, output);
    }
    
    public void setup() {
      colorMode(RGB, 1, 1, 1);
      image = loadImage("Less Rooms.bmp");
      generator = new Generator(toArray(image), 3, 1.2, 32, 32);
      updateOutput();
    }
    
    public void draw() {
      image(image, 0, 0, 128, 128);
      image(output, 128, 0, 128, 128);
    }
    
    @ Override
      public void keyPressed() {
      generator.iterate();
      updateOutput();
    }
    //}
    
    import java.util.HashMap;
    import java.util.Random;
    
    public class Generator {
      public double temperature;
      public Random random;
      public boolean[][] field;
      public final double DEFAULT_WEIGHT = 0.01;
    
      private int N;
      private int width;
      private int height;
    
      public int getWidth() {
        return width;
      }
    
      public int getHeight() {
        return height;
      }
    
      private Pattern[] patterns;
      private HashMap<Integer, Double> weights;
    
      public Generator(boolean[][] sample, int N, double temperature, int width, int height) {
        this.N = N;
        this.temperature = temperature;
        this.width = width;
        this.height = height;
        this.random = new Random();
        this.field = new boolean[width][height];
        this.weights = new HashMap<>();
    
        for (int y = 0; y < sample[0].length; y++) {
          for (int x = 0; x < sample.length; x++) {
            Pattern[] p = new Pattern[8];
            p[0] = new Pattern(sample, x, y, N);
            p[1] = p[0].getRotated();
            p[2] = p[1].getRotated();
            p[3] = p[2].getRotated();
            p[4] = p[0].getReflected();
            p[5] = p[1].getReflected();
            p[6] = p[2].getReflected();
            p[7] = p[3].getReflected();
            for (int k = 0; k < 8; k++) {
              weights.put(p[k].getIndex(), weights.getOrDefault(p[k].getIndex(), 0.) + 1.);
            }
          }
        }
    
        //weights.replaceAll((pattern, weight) -> {
        //    if (weight <= 0.)
        //        return DEFAULT_WEIGHT;
        //    else
        //        return weight;
        //});
        // replaced with:
        for (Integer i : weights.keySet()) {
          if (weights.get(i) <= 0) {
            weights.put(i, DEFAULT_WEIGHT);
          }
        }
    
        for (int y = 0; y < height; y++) {
          for (int x = 0; x < width; x++) {
            field[x][y] = random.nextBoolean();
          }
        }
      }
    
      double energyExp(int i, int j) {
        double value = 1.0;
        for (int y = j - N + 1; y <= j + N - 1; y++) {
          for (int x = i - N + 1; x <= i + N - 1; x++) {
            value *= weights.getOrDefault(new Pattern(field, x, y, N).getIndex(), DEFAULT_WEIGHT);
          }
        }
        return value;
      }
    
      void metropolis(int i, int j) {
        double p = energyExp(i, j);
        field[i][j] = !field[i][j];
        double q = energyExp(i, j);
    
        if (Math.pow(q / p, 1.0 / temperature) < random.nextDouble()) {
          field[i][j] = !field[i][j];
        }
      }
    
      public void iterate() {
        for (int k = 0; k < width * height; k++) {
          metropolis(random.nextInt(width), random.nextInt(height));
        }
      }
    }
    
    
    class Pattern {
      public boolean[][] data;
    
      private int getSize() {
        return data.length;
      }
    
      // new
      private void setValue(boolean value) {
        for (int j = 0; j < getSize(); j++) {
          for (int i = 0; i < getSize(); i++) {
            data[i][j] = value;
          }
        }
      }
    
      //public Pattern(int size, BiPredicate<Integer, Integer> f) {
      //  data = new boolean[size][size];
      //  for (int j = 0; j < getSize(); j++) {
      //    for (int i = 0; i < getSize(); i++) {
      //      data[i][j] = f.test(i, j);
      //    }
      //  }
      //}
    
      // new
      public Pattern(int size, boolean value) {
        data = new boolean[size][size];
        for (int j = 0; j < getSize(); j++) {
          for (int i = 0; i < getSize(); i++) {
            data[i][j] = value;
          }
        }
      }
    
      public Pattern(boolean[][] field, int x, int y, int size) {
        //this(size, (i, j) -> false);
        // replaced with
        this(size, false);
        //Set((i, j) ->
        //  field[(x + i + field.length) % field.length]
        //  [(y + j + field[0].length) % field[0].length]);
        // replaced with:
        for (int i = 0; i < size; i++) {
          for (int j = 0; j < size; j++) {
            int i1 = (x + i + field.length) % field.length;
            int i2 = (y + j + field[0].length) % field[0].length;
            data[i][j] = (field[i1][i2]); // NOT setValue(field[i1][i2]);
          }
        }
      }
    
      public Pattern getRotated() {
        //return new Pattern(getSize(), (x, y) -> data[getSize() - 1 - y][x]);
        // replaced with
        Pattern rotated = new Pattern(getSize(), false);
        for (int x = 0; x < getSize(); x++) {
          for (int y = 0; y < getSize(); y++) {
            rotated.data[x][y] = data[getSize() - 1 - y][x];
          }
        }
        return rotated;
      }
    
      public Pattern getReflected() {
        //return new Pattern(getSize(), (x, y) -> data[getSize() - 1 - x][y]);
        // replaced with
        Pattern reflected = new Pattern(getSize(), false);
        for (int x = 0; x < getSize(); x++) {
          for (int y = 0; y < getSize(); y++) {
            reflected.data[x][y] = data[getSize() - 1 - x][y];
          }
        }
        return reflected;
      }
    
      public int getIndex() {
        int result = 0;
        for (boolean[] row : data) {
          for (boolean datum : row) {
            result <<= 1;
            result += datum ? 1 : 0;
          }
        }
        return result;
      }
    }
    
  • ok, fixed. error was line 221

  • edited November 2017

    @jeremydouglass
    Nevermind, obviously I was trying to run the main java file like a dummy.
    @GoToLoop
    Oh dear I hadnt anticipated it was going to be this complicated...im not familiar at all with this lamda stuff.

    @koogs
    You can run it in netbeans? (never heard of this) I'd like to run it in processing if possible...such a cool code.
    Might be a bit beyond my skills....let me know if you figure it out

  • edited November 2017

    There is also a javascript port of a later version: https://github.com/kchapelier/wavefunctioncollapse (which includes colour) and a python version: https://github.com/ikarth/wfc_python (colour)

  • let me know if you figure it out

    you mean like in the post directly above that one? posted 90 minutes earlier?

    that huge slab of code is the processing version.

  • edited November 2017

    @koogs
    Oh, haha! I thought you were just reposting the original main.java...so you actually have it working in processing on your end? Im not understanding what I would need to do to make it run....you have the pattern.java and generator.java together in that slab of code?
    I have the original images in a folder called data, like you say.
    I get a: unexpected token: href

  • tabs in processing are a falsehood, just there for organisational purposes. that code has the Pattern and Generator classes in it, which is enough.

    cut and paste the entire thing into the editor, add the image using the menu or drag and drop and hit ctrl-r to run.

  • it's not very spectacular.

  • @koogs I see. Its not working for me though, im getting the error
    "unexpected token: href"..?
    I have the same images in the data folder.

  • Line 69 should just be @Override. The forum software breaks things.

  • Ah, think you can post it to pastebin? :3 Im getting a different error now: unexpected token > on line 107

  • Ah, ok, I think the pattern and generator classes have to be in files with .java extensions. I'll fork it on github.

  • here: https://github.com/acdean/ConvChainProcessing

    download as zip file, unzip into your sketchbook and it should run.

  • @koogs
    Wow! You rock man! Just one question, I want to remove the sample image from the processing window (which I have done) but how do I centre the output image to fill up the entire window?
    https://imgur.com/a/znK2J
    Clicking the up and down arrows seems to make it iterate, not sure if there are other keys im missing. Great work.

  • line 66 is the drawing. image(output, 128, 0, 128, 128); top left corner is at 128, 0 and is 128x128 in size. see the reference.

    line 70 - any key makes it iterate.

    i'm still not sure what it does, what it's for...

  • Oh, I was also attempting to convert it. But for now my custom version is buggy! 3:-O
    I've tried to make the boolean[][] array to represent row × col instead, but I've failed! X_X

    Nonetheless, gonna leave its download link here for now: 8-X
    https://GitHub.com/GoToLoop/ConvChainP5/releases

  • edited November 2017

    @koogs Got it now, thanks :) Looks great!
    @GoToLoop I dont get whats wrong with it? Looks good to me, is it because you can't scale it bigger? How would I do that? ...ohh, changing the grid size is nice!!

  • edited November 2017

    Also if anyone feels up to the task...the colour version is probably a lot cooler: https://github.com/kchapelier/wavefunctioncollapse
    ...this is the javascript version. Has other options like N amount and symmetry.

Sign In or Register to comment.