Right way to draw several lines with ofPolyline


#1

Hi there!
im trying to make simple tool for drawing lines using ofPolyline and wanted to ask how to draw more than one line. In most of the tutorials people draw a line and when pressing mouse button to draw another the previous one is cleared. I managed to make it following this tutorial - http://openframeworks.cc/ofBook/chapters/intro_to_graphics.html . In this tutorial you draw a line and in order to save it you copy it by adding it to a vector - is this the only way how to do it? Is there any simplier way?

My main problem is - im trying to make the second created line move but it wont cooperate and i dont understand why. Can anyone help please? Thanks! (sorry if its a dumb question, im a new to OF and c++) :slight_smile:
My code:

header:

		ofPolyline line;
	ofPolyline polyline;

	vector <ofPolyline> polylines;
	vector <ofVec3f> vertices;

ofApp.cpp:

void ofApp::update()
{
	for (int i = 0; i < polyline.getVertices().size(); i++)
	{
		polyline.getVertices()[i].x += ofRandom(-0.5, 0.5);
		polyline.getVertices()[i].y += ofRandom(-0.5, 0.5);
	}
}

void ofApp::draw()
    {
    	ofVec3f mousePos(ofGetMouseX(), ofGetMouseY());
    	line.draw();
    	for (int i = 0; i < polylines.size(); i++)
    	{
    		polyline = polylines[i];
    		polyline.simplify(0.5);
    		polyline.draw();
    	}

    void ofApp::mouseDragged(int x, int y, int button)
{
	ofPoint pt;	
	pt.set(x, y);
	line.addVertex(pt);
}

    void ofApp::mouseReleased(int x, int y, int button)
{
	polylines.push_back(line);
	line.clear();
}

#2

Hi :slight_smile: I’m not sure what you mean with moving the second line. Maybe this gets you started?

// .h
std::vector <ofPolyline> polylines;

// .cpp
#include "ofApp.h"

void ofApp::setup() {
    // have at least one polyline in the vector so we can add points to it
    polylines.push_back(ofPolyline());
}

void ofApp::update() {
    // shake all the points in the line being drawn
    // iterate over all vertices from the latest line
    for (auto & v : polylines.back().getVertices()) {
        v.x += ofRandom(-0.5, 0.5);
        v.y += ofRandom(-0.5, 0.5);
    }
}

void ofApp::draw() {
    // draw all lines. & means reference, this way you access the original
    // instead of creating a copy
    for (auto & line : polylines) {
        line.draw();
    }
}

void ofApp::mouseDragged(int x, int y, int button) {
    // add a vertex and simplify the line being drawn
    polylines.back().addVertex(x, y);
    polylines.back().simplify(0.5);
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button) {
    // add a new line to the vector
    polylines.push_back(ofPolyline());
}


#3

Hello @hamoid

thank you so much! I would probably be able to achieve the same result with my code if i change “polyline” to “line” in my for loop in update function right? But i would like to keep that noise also after you realese the mouse. I was trying really hard but cannot really get around.

By moving the second line i ment - i want to draw a line and let say after a few seconds a want it to curve, zig zag, uncurve, streighten etc… :slight_smile: or when you come close with the mouse cursor…

Hope that makes sence :blush:

I.


#4

Hi! Sometimes it can be hard to understand the idea behind someone else’s code (not that it’s good or bad, just the purpose).

I think I see your issue. polyline = polylines[i] creates a new copy of each polyline, then you simplify and draw this copy. In update it moves the points of that copy. But the next time you visit draw(), you again make copies of the vertices in the vector, overwriting the randomized points.

It’s not like in java, where an equal sign creates something like a reference to the original. I think you could either A) create a reference (in this case it would not work because references always point to the same object, they can’t be updated to point to the latest line), or B) use a pointer:

// .h
        ofPolyline line;
        ofPolyline * polyline = nullptr;

        std::vector <ofPolyline> polylines;
        std::vector <ofVec3f> vertices;

// .cpp

#include "ofApp.h"

void ofApp::update() {
    // until you draw something polyline is null, so you can't get it's vertices
    if(polyline != nullptr) {
        for (auto & v : polyline->getVertices()) {
            v.x += ofRandom(-0.5, 0.5);
            v.y += ofRandom(-0.5, 0.5);
        }
    }
}

void ofApp::draw() {
    ofVec3f mousePos(ofGetMouseX(), ofGetMouseY());
    line.draw();
    for (auto & l : polylines) {
        l.simplify(0.5);
        l.draw();
        // updating polyline here crashes
    }
}

void ofApp::mouseDragged(int x, int y, int button) {
    line.addVertex(x, y);
}

void ofApp::mouseReleased(int x, int y, int button) {
    polylines.push_back(line);
    line.clear();
    // make polyline point to the most recent line
    polyline = &polylines.back();
}

Does that help?

ps. or maybe easier: store the index of the polyline you want to shake as an int, so you would have int polylineId instead of ofPolyline polyline.


#5

Sorry its my fault i could have explained better. Yes this helps a lot! After a bit of struggling with understanding of pointers i think i get it now. So now it basically works like this: by dragging i create line and by releasing i copy it to a vector polylines, delete the original one and make pointer point at it. And because of the pointer i can edit it in update where i than point to its vertices and randomize them. And what if i want to draw several normal not-randomized lines and than after some time make the program pick one by random and shake it? I tried something like this but it does not work:

void ofApp::update() 
{
	float time = ofGetElapsedTimef();

	if (time > 10)
	{
		polyline = &polylines[ofRandom(polylines.size())];

		// until you draw something polyline is null, so you can't get it's vertices
		if (polyline != nullptr)
		{
			for (auto & v : polyline->getVertices())
			{
				v.x += ofRandom(-0.5, 0.5);
				v.y += ofRandom(-0.5, 0.5);
			}
		}
	}

}

and i commented polyline = &polylines.back(); out from mouseReleased function. But instead of one being shaked they all start to move. Is this not the right way how to pick random element from vector?


#6

What’s happening is that after 10 seconds the program constantly picks a new line to shake its vertices, so the effect is that they all shake. You could do something like this to switch the target only sometimes:

// 3% probability of choosing a new target line
if(ofRandom(100) < 3) {
    polyline = &polylines[ofRandom(polylines.size())];
}

#7

Sorry for the late reply i was a bit busy… Thank you som much, now its working :slight_smile: