Using ofNode to build an L-System

Hello, I’m trying to use ofNode to make an L-System. I’m having problem getting the rotation of an ofNode respect to another properly.
That is my code


//App.h
ofVboMesh mesh;
std::deque<Branch>  bookmarks;

//Branch.h

class Branch: public ofNode{
    ofNode translation;
    
public:
    Branch(){
        ofNode::setParent(translation); // this calls the ofNode version of setParent
        // avoiding a recursive call when calling our own version
    }
    
    void preTranslate(ofVec3f t){
        translation.move(t);
    }
    
    void setParent(ofNode & node){
        translation.setParent(node);
    }
};

//ofApp.cpp
//--------------------------------------------------------------
void ofApp::setup(){
    mesh.setMode(OF_PRIMITIVE_POINTS);
    mesh.enableColors();
    
    ofNode root = ofNode();
    root.setPosition(450, 700, 0);
    auto branch = Branch();
    branch.setParent(root);
    
    string _instruction = "F+F+F";
    
    for (int i = 0; i < _instruction.length(); i++) {
        char c = _instruction[i];
        if (c == 'F') {
            if(mesh.getNumVertices() == 0){
                //add the first branch to the root
                branch.preTranslate(ofVec3f(0, -100, 0));
                mesh.addVertex(branch.getGlobalPosition());
                mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
            }else{
                //add a new branch
                auto newBranch = Branch();
                newBranch.setParent(branch);
                newBranch.move(ofVec3f(0, -100,0));
                mesh.addVertex(newBranch.getGlobalPosition());
                mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
                
                branch.preTranslate(ofVec3f(0, -100, 0));
            };
        }else if( c == 'G') {
            branch.move(ofVec3f(0, -100, 0));
        }else if (c == '+') {
            branch.roll(25.00);
        }
        else if (c == '-') {
            branch.roll(-25.00);
        }
        else if (c == '[') {
            bookmarks.push_back(branch);
        }
        else if (c == ']') {
            branch = bookmarks.back();
            bookmarks.pop_back();
        }
    }
}

What I would like is this:

What I’m aiming for is this:

Basically, i would like that the rotation of each node is relative to the previous node.
Someone has an idea about how to fix it? also suggestion for another approach are welcome.
The code is available here https://github.com/edap/testRotation

Out of the loop it is easier because i can recreate a new ofNode for every point, and the transformation are in the correct order (before the rotation and after the translation)

    ofNode root = ofNode();
    root.setPosition(450, 700, 0);
    auto branch = ofNode();
    branch.setParent(root);
    branch.roll(45.00);
    branch.move(ofVec3f(0, -100, 0));
    mesh.addVertex(branch.getGlobalPosition());
    mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
    
    auto branch2 = ofNode();
    branch2.setParent(branch);
    branch2.roll(45.00);
    branch2.move(ofVec3f(0, -100, 0));
    mesh.addVertex(branch2.getGlobalPosition());
    mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
    
    auto branch3 = ofNode();
    branch3.setParent(branch2);
    branch3.roll(45.00);
    branch3.move(ofVec3f(0, -100, 0));
    mesh.addVertex(branch3.getGlobalPosition());
    mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));

I think that the problem is in the copy of the ofNode. I’ve edited the previous code as follow, removing the pre-translation and using directly ofNode.

    ofNode root = ofNode();
    root.setPosition(450, 700, 0);
    auto branch = ofNode();
    branch.setParent(root);

    bool branching = false;
    
    string _instruction = "F+F+F";
    mesh.clear();
    
    for (int i = 0; i < _instruction.length(); i++) {
        char c = _instruction[i];
        if (c == 'F') {
            branching = true;
        }else if (c == '+') {
            branch.roll(25.0);
        }
        
        if(branching){
            if(mesh.getNumVertices() == 0){
                //add the first branch to the root
                branch.move(ofVec3f(0, -100, 0));
                cout << branch.getGlobalPosition().y << endl;
                mesh.addVertex(branch.getGlobalPosition());
                mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
                branching = false;
            }else{
                //add a new branch
                auto oldBranch = ofNode(branch);
                auto branch = ofNode();
                branch.setParent(oldBranch);
                branch.move(ofVec3f(0, -100,0));
                mesh.addVertex(branch.getGlobalPosition());
                mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
                branching = false;
            };
        }
    }

I think the problem is here

auto oldBranch = ofNode(branch);
auto branch = ofNode();
branch.setParent(oldBranch);

What I would like to do is that oldBranch save the position of branch accumulated until now, and auto branch = ofNode() create a new ofNode, re-assigning the value of branch. What is happening is that branch it is not re-assigned. It remains the same as at the beginning.
Some ideas?

if you want the rotation of a node to be relative to the previous one you can just rotate the previous one or add a third node that is the one which rotates and is parented to the previous one.

@arturo Do you mean something like this?

    for (int i = 0; i < _instruction.length(); i++) {
        char c = _instruction[i];
        if (c == 'F') {
            branching = true;
        }else if (c == '+') {
            auto jointBranch = Branch();
            jointBranch.setParent(branch);
            jointBranch.roll(45);
            auto branch = Branch();
            branch.setParent(jointBranch);
        }
        
        if(branching){
            if(mesh.getNumVertices() == 0){
                //add the first branch to the root
                branch.move(ofVec3f(0, -100, 0));
                mesh.addVertex(branch.getGlobalPosition());
                mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
                branching = false;
            }else{
                //add a new branch
                auto oldBranch = Branch(branch);
                auto branch = Branch();
                branch.setParent(oldBranch);
                branch.move(ofVec3f(0, -100,0));
                mesh.addVertex(branch.getGlobalPosition());
                mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
                branching = false;
            };
        }

This is also not working, i think the problem is re-assigning a ofNode. This is the output of this code:

I think that with ofNode it should be possible to do inside a loop what is done in the snippet posted here Using ofNode to build an L-System
If it is not, it should be documented somewhere how to copy a ofNode.
I will experiment a bit again, and if it does not work I will simply use Vectors

not sure what you are trying to do but things like:

        if (c == 'F') {
            branching = true;
        }else if (c == '+') {
            auto jointBranch = Branch();
            jointBranch.setParent(branch);
            jointBranch.roll(45);
            auto branch = Branch();
            branch.setParent(jointBranch);
        }

don’t make much sense since that last auto branch is being deleted right away after that block ends

Thanks @arturo for the answer. What i meant to do with that auto branch was to re-assigne the value of the variable branch, defined before the loop starts, https://github.com/edap/testRotation/blob/master/src/ofApp.cpp#L46

What I’m trying to do is simply to use ofNode in a loop in order to draw this:

https://forum.openframeworks.cc/uploads/default/original/2X/3/314f0e4bcf8eb668993a825affa4e139067896ff.png

This commented part https://github.com/edap/testRotation/blob/master/src/ofApp.cpp#L9 does what i want, but i need to do it in a loop.
I hope is it clear enough.

ah, ok then you shouldn’t use auto, using auto there is like declaring a new variable only visible in that block. just use branch=... like:

        if (c == 'F') {
            branching = true;
        }else if (c == '+') {
            auto jointBranch = Branch();
            jointBranch.setParent(branch);
            jointBranch.roll(45);
            branch = Branch();
            branch.setParent(jointBranch);
        }

you also need to store jointBranch somewhere since it’s also going away as soon as the block ends, perhaps put them in a vector or something like that

Thanks @arturo, i will give it a try as soon as I’m home.

Nope, it is still not working, I’ve a bad memory access. I’ve simplified and pushed the code, removing the part with the L-System grammar that is not the problem.

void ofApp::setup(){
    mesh.setMode(OF_PRIMITIVE_POINTS);
    mesh.enableColors();
    
    auto joinBranch = ofNode();
    auto oldBranch = ofNode();
    auto newBranch = ofNode();
    
    oldBranch.setPosition(150, 700, 0);
    oldBranch.move(ofVec3f(0, -100, 0));
    mesh.addVertex(oldBranch.getGlobalPosition());
    mesh.addColor(ofFloatColor(1.0, 0.0, 0.0));
    
    for(int i = 0; i < 4; i++){
        joinBranch = ofNode();
        joinBranch.setParent(oldBranch);
        joinBranch.roll(25.0);
        
        newBranch = ofNode();
        newBranch.setParent(joinBranch);
        newBranch.move(0, -100.0, 0);
        
        mesh.addVertex(newBranch.getGlobalPosition());
        mesh.addColor(ofFloatColor(1.0, 0.0, 0.0));
        
        //reassign oldBranch value
        oldBranch = newBranch;
    }
}

void ofApp::draw(){
    ofBackground(0);
    mesh.draw();
}

I do not need to keep the jointBranch in a vector, because what i need are just the points in the mesh.

yes but when you do joinBranch = ofNode(); in the second iteration the previous joinBranch gets deleted and the so the parent for oldBranch is not valid anymore so the program crashes. this is not java things allocated in the stack get deleted right away. when you do joinBranch.setParent(oldBranch); you are passing a reference to the original but you are responsible to keep that parent alive for the same scope as the child.

Thanks @arturo, i come from “another world” than the c++ one. It works

void ofApp::setup(){
    mesh.setMode(OF_PRIMITIVE_POINTS);
    mesh.enableColors();
    
    vector<ofNode> joinBranchContainer;
    vector<ofNode> branchContainer;
    
    auto branch = ofNode();
    branch.setPosition(150, 700, 0);
    branch.move(ofVec3f(0, -100, 0));
    mesh.addVertex(branch.getGlobalPosition());
    mesh.addColor(ofFloatColor(1.0, 0.0, 0.0));
    branchContainer.push_back(branch);
    
    for(int i = 0; i < 4; i++){
        auto newJoin = Branch();
        newJoin.setParent(branchContainer.back());
        newJoin.roll(25.00);
        joinBranchContainer.push_back(newJoin);
        
        auto newBranch = Branch();
        newBranch.setParent(joinBranchContainer.back());
        newBranch.move(ofVec3f(0, -100, 0));
        branchContainer.push_back(newBranch);
        
        mesh.addVertex(newBranch.getGlobalPosition());
        mesh.addColor(ofFloatColor(1.0, 0.0, 0.0));
    }
    joinBranchContainer.clear();
    branchContainer.clear();
}

Just a little worried that these 2 containers will grow too much but for now is ok.

ofNode is around 104 bytes so if you have 2Gb RAM you would need to create around 20 million nodes to use all the available memory