ArrayList on class constructor - Could not run the sketch

Hey there,

I am new to oop and don´t now why my program does not start ... The values that are given into the constructor in the "else" part are public variables frome the object created in the "if". after that always the next branch shell take the variables from the branch created bevor ...

My processing gives me: "NullPointerExeption"

when i run the code the window stays blank. after that it says: "Could not run the sketch"

  // ----- The Branches -------


 public void growBranch() {
// declare the ArrayObject
Branch[] branch;

// Inicialize the ArrayObject
branch = new Branch[branchNumber];

int branchIndex = 0;
for (int i = 0; i < branchNumber; i++) {

  // in the first round the starting length is divided, values are taken from the plant object
  if (i == 1) {
    branch[branchIndex++] = new Branch(targetX, targetY, (startLength/2));
    branch[branchIndex].calcBranch();


    // in all other rounds, values are taken from the last branch object created.
  } else {
    branch[branchIndex++] = new Branch(branch[i].branchTargetX, branch[i].branchTargetY, (branch[i].growLength)/2);
    branch[branchIndex].calcBranch();
          }
        }
    }
}

Thanks i advance. Let me now if i shall provide more of the code

and sry for my bad Englich ; )

Answers

  • What line throws the NullPointerException? What is the value of every variable on that line? Hint: one of them is null. Use print statements to figure that out.

    When you figure that out, you can work backwards to determine why that variable is null, and then you'll be able to fix your error.

  • Thx for the fast reply,

    I went thought the code and just changed some formatting as far as I thing, and now it shows me the same error in my branch object at line 7. but there is just a float variable initialisation.

    I hope its ok if i post the whole thing. I gues im totaly lost here.

    main sketch

        // Declare the object
        Plant plant;
    
        void setup() {
          // Inicialize The object
          plant = new Plant(250, 390, 140);
          size(500, 500);
          smooth();
        }
    
    
        void draw() {
          plant.grow();
          plant.growBranch();
          // Ground rectangle ;)
          rect(0, 400, 500, 100);
        }
    

    Branch Class

        public class Branch {
          // initialize the variables
          private float rootX = 0;
          private float rootY = 0;
    
          private float branchTargetX = 0;
          private float branchTargetY = 0;
    
          private float growLength = 0; // nur für branches
    
          private float alpha = 45;    // branch winkel
    
    
        // Constructor
          public Branch(float rootX, float rootY, float growLength) {
            this.rootX = rootX;
            this.rootY = rootY;
            this.growLength = growLength;
    
          }
    
          // method
    
           public void calcBranch() {
    
    
    
            // erstes target must be defined
            branchTargetX = rootX - ((sin(alpha))*growLength);
            branchTargetY = rootY - sqrt(( (growLength*growLength)  -  ((sin(alpha)*growLength) * (sin(alpha)*growLength)) ));
    
    
            // Branch
            line(rootX, rootY, branchTargetX, branchTargetY);
          }
    
    
          // Return Variables For further Branches
    
          public float growLength() {
            return this.growLength;
          }
    
          // Give target X und Y for the New operator in the plant class
          public float branchTargetX() {
            return this.branchTargetX;
          } 
          public float branchTargetY() {
            return this.branchTargetY;
          }
        }
    

    Plant Class

        public class Plant {
    
    
    
          // initialise the variables
          private float rootX = 0;
          private float rootY = 0;
    
          private float targetX = 0;
          private float targetY = 0;
    
          private int branchNumber = 2;
    
          private float startLength = 0; // Nur für stamm
    
          private float alpha = 0;        // Start Winkel
    
    
          // Constructor
    
    
          public Plant(float rootX, float rootY, float startLength) {
            this.rootX = rootX;
            this.rootY = rootY;
            this.startLength = startLength;
          }
    
          public void grow() {
    
    
    
            // erstes target must be defined
            targetX = rootX - ((sin(alpha))*startLength);
            targetY = rootY - sqrt(( (startLength*startLength)  -  ((sin(alpha)*startLength) * (sin(alpha)*startLength)) ));
    
    
            // Stamm
            line(rootX, rootY, targetX, targetY);
          }
    
    
    
          // ----- The Branches -------
    
    
          public void growBranch() {
            // declare the ArrayObject
            Branch[] branch;
    
            // Inicialize the ArrayObject
            branch = new Branch[branchNumber];
    
            int branchIndex = 0;
            for (int i = 0; i < branchNumber; i++) {
    
              // in the first round the starting length is divided, values are taken from the plant object
              if (i == 1) {
                branch[branchIndex++] = new Branch(targetX, targetY, (startLength/2));
                branch[branchIndex].calcBranch();
    
    
                // in all other rounds, values are taken from the last branch object created.
              } else {
                branch[branchIndex++] = new Branch(branch[i].branchTargetX, branch[i].branchTargetY, (branch[i].growLength)/2);
                branch[branchIndex].calcBranch();
              }
            }
          }
        }
    

    Goal is to hopfully later create Plants with that.

  • The problem seems to stem (no pun intended) from your growBranch() method. I don't have time to pick over it in detail; but it feels wrong to be declaring the branch array within the growBranch method. If the Plant grows branches then these are a property of the Plant and should surely be declared at its root (again no pun intended :) )...

  • edited May 2015

    You should make Branch, and any other future parts, a fixed property of Plant.
    Take a look at this thread about a class CircleMatrix which itself instantiates and stores Circle objects:

    1. http://forum.processing.org/two/discussion/11034/problem-with-positioning-object-on-grid
    2. http://studio.processingtogether.com/sp/pad/export/ro.9Ix4oqMF4OK6g/latest
  • hm, i think i don´t really get that. declaring the branch array at the root means just put it into the Class instead of the method ? When i just copy it over there it says" unexpected token: branch " ???

  • My comment wasn't suggesting a specific code change but a change to the general structure. After your branches have grown you might want to make them move. You will probably want to do this in relation to the plant, so it would make sense to be able to reference them from there...

    I may be able to post some example code later ;)

  • @GoToLoop

    Thx for the example it really helps me learning

    @blindfisch

    ok i get it. I doesn´t work yet but i think you brought me on the right path i gues

    ;) Thx again...

  • In terms of specifics branch[branchIndex++] in your if(i == 1) statement is almost certainly the root cause of your error. If i=1, then branchIndex will also be 1 when the condition is true. You then add 1 to it with the above, so it's value is 2 when you use it in branch[branchIndex].calcBranch(). Remember that arrays start at 0 so 2 is out of bounds...

    You shouldn't need the branchIndex variable at all and should be able to do what you want by simply referencing the value of i

  • Just also noticed that you're setting some variables in your class to private. IIRC that's not supported in Processing...

  • IIRC that's not supported in Processing...

  • So you're implying it has not effect?

    In practice when I ran @Barashy's code, the Processing IDE was flagging the private branchTargetX/Y vars with a null-pointer exception. Once I removed the private flag from the variables the IDE correctly identified the line in which the error was occurring. That would seem to imply that slapping 'private' on your variables is going to make debugging more complex - ergo "not supported" :P

  • edited June 2015 Answer ✓

    @Barashy: it's a while since I had a go at something like this. I just found time to set up a proof of concept and was reminded of the main difficulty - splitting each branch into sub-branches - which is probably what led you to your rather convoluted use of branchIndex++ when assigning to your branch array.

    So here's a somewhat simpler implementation with just a single class (though see my note below):

    Edit: made changes to calculation of angle to correct error in trig equations. As yet untested so this may 'break' the rendered output slightly...

    sketch

    int numBranches = 48;
    Branch[] branches = new Branch[numBranches];
    
    void setup() {
      size(600, 500);
      int counter = 0;
      for(int i=0; i<numBranches; i++) {
        // the trunk
        if(i==0) {
           branches[i] = new Branch(width/2, height, 100); 
        }
        else {
          // counter is used to set the parent of a branch
          branches[i] = new Branch(branches[counter], 30 + random(60), random(90) );
    
          // Using modulo here allows 'counter' to be incremented once every two iterations;
          // meaning each branch has ~two sub-branches.
          // Alternatively you could use a nested loop.
          // However you go about doing this you have to make sure you remain
          // within the bounds of the array!
          int foo = 1 - i % 2;
          counter += foo;
        }
      }
    }
    
    void draw() {
      background(230,230,170);
      stroke(0, 50);
      strokeWeight(8);
    
      for(int i=0; i<numBranches; i++) {
        branches[i].render();
      }
    
    }
    

    Branch

    class Branch {
    
     float x1, y1;// used only in root
     Branch parent;// used by higher branches
     float x2, y2;
     Boolean isSubBranch = true;
     float len;
     float angle;
    
      // constructor for trunk
      Branch(float startX, float startY, float len) {
       this.isSubBranch = false;
       this.x1 = startX;
       this.y1 = startY;
       this.len = len;
       calcTipPosition();
      }
    
      // constructor for higher branches
      // These reference the parent trunk/branch 
      // to get their starting point 
      Branch(Branch parent, float len, float angle) {
        this.parent = parent;
        this.len = len;
        this.angle = radians(angle);
        calcTipPosition();
      }
    
      // calculate branch tip position based on start and angle
      void calcTipPosition() {
        if(isSubBranch) {
          this.x2 = parent.x2 - cos(angle) * len;
          this.y2 = parent.y2 - sin(angle) * len;
        }
        else {
          this.x2 = x1 - cos(angle) * len;
          this.y2 = y1 - sin(angle) * len;
        }
      }
    
      void render() {
         if(isSubBranch) {
           line(parent.x2, parent.y2,x2,y2);
         }
         else {
           line(x1,y1,x2,y2);
         }
      }
    
    }
    

    There's a lot of room for improvement and added features - e.g. changing branch thickness, setting more rational angles, splitting into more branches. I'd also feel more comfortable with a separate Trunk class, with Branch probably inheriting from this, to separate the behaviour of the two objects.

    The key point is that branches are stored in an array at the root of the sketch (but this could be at the root of your Plant class). That means you can iterate over your branches and update them each frame; and that will allow you to add animation...

  • edited June 2015 Answer ✓

    @Barashy ... As I said above: it's a while since I tried anything like this so I thought I'd have a go at expanding on the above in p5js; since that's what I'm trying to concentrate my time on these days.

    The following code uses a single for loop to generate all the branches of the tree. I tried nested loops; but that wasn't as flexible. I suspect a recursive function might also be an option. Anyway - the loop works by using some variables to count progress as each branch is populated with sub-branches. I had to draw the tree out on paper and do some proper thinking (for a change) to figure the best way to set the loop limit to ensure all branches are evenly populated. I also created a separate trunk class.

    Since this is for P5 it's JavaScript based; but the concepts should be equally applicable in Processing/Java. I've tried to remove extraneous code; but there may be a few redundant bits and pieces...

    Note to any P5 users wanting to test this: classes should be loaded before sketch.js! The blindfish object is a way of keeping the global namespace clean and is IMHO recommended when working in JavaScript...

    sketch

    blindfish.p5 = new p5(function (p) {
    
        var trunk,
            branches = [],
            levels = 5,
            maxSplits = 3,
            // Setting the limit turns out to be fiddly
            // This should work for any combination of levels/maxSplits
            //TODO: I suspect there's a way to optimise this!
            limit = (function () {
                var total = 0;
                for (var i = 1; i < levels; i++) {
                    var power = Math.pow(maxSplits, i);
                    total += power;
                }
                return total;
            })();
    
    
        p.setup = function () {
            p.createCanvas(600, 400);
    
            var branchCounter = -1,// track which branch sub-branches are being added to
                splitCounter = 1,// track the number of sub-branches added to the current branch
                thisParent;
            trunk = new blindfish.Trunk(p.width / 2, p.height, p.width / 2, p.height - 80);
    
    
    
            for (var i = 0; i < limit; i++) {
                // -1 == the trunk
                if (branchCounter === -1) {
                    thisParent = trunk;
                }
                else {
                    thisParent = branches[branchCounter];
                }
    
                //TODO:  This needs improvement!
                // 1. to make it work with all variations without manual intervention
                // 2. to offset from parent angle
    
                // Note: added some randomness to produce a more 'natural' result.
                // Note: because this doesn't reference the parent angle there's a
                // high concentration of branches in the middle of the tree
                // edited this to work with fix to Branch.calcTipPosition()
                var newAngle = p.radians(60 * splitCounter) - Math.random() *0.5 - 0.25;
    
                branches[i] = new blindfish.Branch(trunk, thisParent, 50, newAngle);
    
                // once you've added all sub-branches to the current branch
                if (splitCounter >= maxSplits) {
                    // move to the next branch
                    branchCounter++;
                    // reset the sub-branch counter
                    splitCounter = 0;
                }
                // increment the sub-branch counter
                splitCounter++;
            }
    
        };
    
    
        p.draw = function () {
            p.background(255);
            p.stroke(200, 166, 0, 50);
            trunk.draw();
            for (var i = 0; i < limit; i++) {
                branches[i].draw();
            }
        };
    
    
    }, "sketch01");
    

    classes

    var blindfish = blindfish || {};
    
    // - - - CLASS TRUNK - - - //
    blindfish.Trunk = function (startX, startY, endX, endY, len ) {
    
      this.rootX = startX;
      this.rootY = startY;
      this.tipX = endX;
      this.tipY = endY;
      this.length = len;  
      this.weight = 16;
      this.level = 0;  
      this.angle = Math.atan2(startY-endY, startX-endX);   
    };
    
    blindfish.Trunk.prototype.draw = function () {
        var p = blindfish.p5; 
        p.strokeWeight(this.weight);
        p.line(this.rootX, this.rootY, this.tipX, this.tipY);   
    }
    
    
    // - - - CLASS BRANCH - - - //
    blindfish.Branch = function(trunk, parent, len, angle) {       
        this.parent = parent;
        this.trunk = trunk;
        this.length = len;
        this.angle = angle;
        this.level = this.parent.level + 1;
        this.calcTipPosition();
    };
    
    blindfish.Branch.prototype.calcTipPosition = function () {
        var parent = this.parent;
        // edit: fixed this: I had cos/sin the wrong way round...
        this.tipX = parent.tipX - Math.cos(this.angle) * this.length;
        this.tipY = parent.tipY - Math.sin(this.angle) * this.length;
    }
    
    blindfish.Branch.prototype.draw = function () {
        var p = blindfish.p5; 
    
        p.strokeWeight(this.trunk.weight/this.level);
        p.line(this.parent.tipX, this.parent.tipY, this.tipX, this.tipY);
    
    }
    
  • Hi,

    first of all sry for the delay but i was very busy these days.
    Thank you again! i wan´t expecting that so quick and so helpful replies. I´m realy trying to come forword with programing these days and your feed back as well realy got me on the track. I think beside you showed me a great example of how to do it there is also lots of potential to learn towards a more general understanding of code. I´ll try to return that help to this forum in at other places to strength this great community.

    Sry again for my medium english skills ;)

  • @Barashy: no worries. I quite enjoyed the challenge :)

    I've already updated my p5 code to fix some of the issues I had noted in the above and also made it so branches are added from within the 'Trunk class' (which I should now rename 'Tree' or even 'Plant'!). This basically involves moving relevant variables into the Trunk class and running the for loop currently in setup when a new Trunk is created (I've added it as a method of Trunk). I won't post any updated code here just yet; but might provide you a link later on ;)

  • edited June 2015

    @Barashy: I've made a lot of updates to my original code: fixed a number of bugs and made various improvements. My up-to-date Tree and Branch classes can be found on github.

    Now I've got my head round Github pages (thanks to this post) I have a live demo. Sorry - I'll have to update the page and source code to give you a credit for starting me on this :)

    There's still room for improvement; and so many features that could be added! One thing I realised is that I got carried away adding features early on; before I was certain the base code was working correctly. I've now fixed various errors that resulted from this. So you'll find I've removed any randomisation from branch length and angle since that was:

    • badly implemented
      To get a balanced range use random() * n - n/2
    • was obscuring the fact my angleStep calculation had an error

    Note that a lot of the additional methods are there to enable live updating of tree and branch properties :)

Sign In or Register to comment.