Getting Global Coordinates from Local Transformations


#1

Hi there!

I have a situtation where I’ll be implementing certain things using ofPushMatrix(), ofTranslate() … etc. Now my need is to get the global coordinates after all these transformations. The only way I can think of (and it works, tested already, code below) is to store each transformation as a separate matrix as well and then I can use them (for each step) for transforming to the local points… but as you can imagine that can get real hairy real fast - so is there a better way of doing this? Getting global coordinates after using pushMatrix, ofTranslate, etc?

ofMatrix4x4 transform, transform2;
ofPoint pointX(0, 0);

ofPushMatrix();
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
transform.setTranslation(ofGetWidth()/2, ofGetHeight()/2, 0);

ofRotateZ(45);
ofTranslate(100, 0);

transform2 = transform;
ofMatrix4x4 localRotate, localTranslate;

auto rotate = ofQuaternion(45, ofVec3f(0, 0, 1));
localRotate.setRotate(rotate);
localTranslate.setTranslation(100, 0, 0);

transform2 = localTranslate * localRotate * transform2;

ofSetColor(ofColor::red);
ofDrawCircle(0, 0, 8);

ofPopMatrix();

transform = ofMatrix4x4::getTransposedOf(transform);
transform2 = ofMatrix4x4::getTransposedOf(transform2);

ofSetColor(ofColor::yellow);
ofDrawCircle(transform2 * pointX, 4);

#2

Depends on your application but ofNode::getGlobalPosition() can be option


#3

No… that doesn’t work, the problem is that I’m getting the positions only after pushing and translating etc and if I do node.setPosition(0, 0, 0); from inside the pushed state, it doesn’t save the local coordinates of the position there.


#4

This might work:

ofMatrix4x4 ofGetCurrentMatrix(ofMatrixMode matrixMode)


#5

Hmm… You might be onto something here. But, it doesn’t work, not the way I’d like it to.

ofMatrix4x4 t;

cout << t << endl; // returns identity

ofPushMatrix();
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
t = ofGetCurrentMatrix(OF_MATRIX_PROJECTION);
ofPopMatrix();


cout << t << endl;

If I do this, I get back;

 1.29904,        0,        0,        0
       0,  1.73205,        0,        0
       0,        0,  -1.0202,       -1
       0,        0, -134.365,        0

What is this…?

(If I try the other options for the matrixMode, none of them returns the correct width/2 and height/2 translation transformation matrix here…)


#6

I am getting there with my earlier thought process though, it’s an L-system that I need to get global positions for.

Goes down one hierarchy fine, the other, not too well. But a bit more of getting my logic right in pushing and popping the matrix stack, it should get there :slight_smile:


#7

there is a matrix stack where the transformations get pushed and popped. search in the OF files for ofMartixStack. You will need to modify some stuff to make it visible (public), although I only recommend this as a last resource.
if you are doing L-Systems maybe it is a better idea to use ofNodes and nest these. For instance, if you have 2 instances of ofNode, say:

ofNode node1, node2;
node1.setParent(node2);

All the transformations of node2 will be reflected on node1 as if these were attached.
There are some examples of this in the 3D folder in the examples.

hope this helps


#8

Thanks! The ofMatrixStack was something I was looking for!

I did consider ofNode and was looking into @edapx thread here as well, but I’m trying to keep it a bit more general for future re-use with regular push, pop, translate functions, so let’s see.

I’m going to investigate the three methods, my approach with linear transformations, the ofMatrixStack and the ofNode option over the next few days and let’s see what works best :slight_smile:


#9

To be honest, I think it is more easy to reuse code written with ofNode, ofNode gives you all what you need just setting parents to each node, it’s more flexible than to pile up stack of matrices that you need to manage by yourself. Once you get used about how it works, you never go back. But maybe it’s a matter of taste


#10

Ok… some updates on this. Obviously, my first approach of getting the transformation matrices for each transform was getting really complicated… but I think it was in the step in the right direction. I didn’t manage to make much progress with ofNode while keeping the code clean so I went back to check how the ofMatrixStack was handling things… and voila! Here’s some results.

ofMatrix4x4 master = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);

ofMatrix4x4 m;

m = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);
cout << m - master <<endl;
cout << "-------------------" <<endl;

ofPushMatrix();
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
m = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);
ofPopMatrix();

cout<< m - master<<endl;
cout << "-------------------" <<endl;

ofPoint p(0, 0);
ofMatrix4x4 translatationMatrix = m - master;
translatationMatrix._mat[3][3] = 1; //fix the homogenous coordinate w
p = p * translatationMatrix;

ofDrawCircle(p, 5);

The first cout prints:

   0,        0,        0,        0
   0,        0,        0,        0
   0,        0,        0,        0
   0,        0,        0,        0

And the second cout prints

   0,        0,        0,        0
   0,        0,        0,        0
   0,        0,        0,        0
 500,      500,        0,        0

So I am getting the translation matrix from here! (The homogenous coordinate is wrong, which I’m fixing forcibly in my code - I did have to define the - operator for Matrices so I could fix it there too). But using that matrix (with the homogenous w fixed) I can transform a global coordinate from the PushMatrix translation (yup, the ofPoint does indeed draw in the centre of my screen!).


#11

And… solved!

I’m modifying the L-System code from here.

In Turtle.h adding,
vector<ofMatrix4x4> transforms;

Turtle.cpp draw function becomes,

if (transforms.size()>0) transforms.clear();

for (int i = 0; i < instructions.length(); i++) {
    char c = instructions[i];
    
    if (c == 'F') {
        ofLine(0, 0, length, 0);
        ofTranslate(length, 0);
        
        ofMatrix4x4 c_ = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);
        transforms.push_back(c_);
        
    }else if( c == 'G') {
        ofTranslate(length, 0);

        ofMatrix4x4 c_ = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);
        transforms.push_back(c_);
        
    }else if (c == '+') {
        ofRotate(theta);
        
        ofMatrix4x4 c_ = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);
        transforms.push_back(c_);
    }
    else if (c == '-') {
        ofRotate(-theta);
        
        ofMatrix4x4 c_ = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);
        transforms.push_back(c_);
    }
    else if (c == '[') {
        ofPushMatrix();
        
    }
    else if (c == ']') {
        ofPopMatrix();

    }
}

And in ofApp.cpp…

ofMatrix4x4 master = ofGetCurrentMatrix(OF_MATRIX_MODELVIEW);

ofPushMatrix();

if (bIsTreeMode) {
    ofTranslate( ofGetWidth()/2, ofGetWindowHeight() );
    ofRotate( -90 );
    
} else {
    ofTranslate(0, ofGetHeight());
    
}

turtle.draw();

ofPopMatrix();

ofPushStyle();
for(int i = 0; i<turtle.transforms.size(); i++){
    ofPoint p(0, 0);
    ofMatrix4x4 transformation = turtle.transforms[i] - master;
    transformation._mat[3][3] = 1;
    p = p * transformation;
    ofSetColor(255, 255, 0, 127);
    ofDrawCircle(p, 3);
}
ofPopStyle();

Here’s a couple of screenshots…

Now, I do think there are a few duplicate ofPoints being drawn, I will have to store them in a vector and go through them and check that (at a later point though!) and this needs a slight addition I did to the ofMatrix4x4.h file, where I defined the minus operator, as below,

inline ofMatrix4x4 operator- (const ofMatrix4x4&m1, const ofMatrix4x4& m2){
    ofMatrix4x4 answer;

    answer._mat[0] = m1._mat[0] - m2._mat[0];
    answer._mat[1] = m1._mat[1] - m2._mat[1];
    answer._mat[2] = m1._mat[2] - m2._mat[2];
    answer._mat[3] = m1._mat[3] - m2._mat[3];
    
    return answer;}

#12

Nice! I’ve done exactly the same a while ago, L-Systems, but using ofNode. If you are interested, here the code