Working with lines!

Hello there,

I have read lot of documentation (class documentation, examples, ofBook…) about working with lines, but stil i have some problem understanding the differences and use cases of the different representations such polyline, path, tesselation and so on.

basically i am trying to deal with shapes from svg files

some explanation would be really great !

ofPolyline: is a way of representing a polyline or polygon (depending if it’s closed) and although it can be drawn it’s mostly thought to be used for doing geometrical calculations on it.

ofPath: is a more complex class that represents any kind of shape, with fill and/or stroke and closed or not, or even a combination of shapes. It can also be drawn and is mainly thought to be used for drawing. It stores the shapes as primitives, so for example if you create a bezier line it’ll store the initial and end point and the control points of the bezier, When drawing it, some renderers, for example openGL doesn’t know how to draw a bezier so you need to send the graphics card a decomposition as line segments. In that case ofPath will decompose that primitive in line segments and store that decomposition as a vector of ofPolyline as a kind of cache so later draws are faster. Some renderers like cairo know how to draw a bezier or other primitives so when using those ofPath will just send the primitives directly

Also, when drawing filled shapes, with opengl you can’t draw filled shapes that are not convex directly, so in order to draw such a shape you need to decompose it in triangles and send those to the graphics card. That’s what’s called tessellation. ofPath does it internally and generates an ofMesh with the decomposition of any filled shape into triangles the first time you try to draw it. It also caches this decomposition so when you try to draw it later it doesn’t need to decompose it every time.

You can access the decomposition of any primitive in an ofPath into ofPolylines (if the path has line width>0) using getOutlines() which returns a vector<ofPolyline>

And the tesselation as an ofMesh (if it has fill, setFilled(true)) with getTesselation()

3 Likes

ok. Thanks this is really helpful !

So for now i have an svg with a yellow filled triangle and a red filled square.

I am trying to grab only the triangle contour shape with its color just to have some tests and see if i understand everything well.

Then i need this shape to be part of the ofxBox2d world so particles can interact with it.

here is what i’ve got so far :

header :

#pragma once

#include "ofMain.h"
#include "ofxBox2d.h"
#include "ofxSvg.h"

class ofApp : public ofBaseApp{

	public:

	void setup();
	void update();
	void draw();

	void keyPressed(int key);
	void keyReleased(int key);
	void mouseMoved(int x, int y );
	void mouseDragged(int x, int y, int button);
	void mousePressed(int x, int y, int button);
	void mouseReleased(int x, int y, int button);
	void windowResized(int w, int h);
	void dragEvent(ofDragInfo dragInfo);
	void gotMessage(ofMessage msg);

ofxBox2d box2d;
vector<shared_ptr<ofxBox2dCircle> > boxCircles;
ofxBox2dEdge edgeLine;

ofPolyline drawing;
ofPath shape;

ofxSVG svg;		
};

source :

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    box2d.init();
    box2d.createBounds();
    box2d.setFPS(60.0);
    
    svg.load("1.svg");
    
    shape = svg.getPathAt(0);
    shape.setStrokeColor(ofColor::yellow);
    shape.setStrokeWidth(5);
    
    drawing = shape.getOutline().at(0);
    
    edgeLine.addVertexes(drawing);
    edgeLine.setPhysics(0.0, 0.5, 0.5);
    edgeLine.create(box2d.getWorld());

    
}

//--------------------------------------------------------------
void ofApp::update(){
    box2d.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    box2d.draw();
    //shape.draw();
    edgeLine.draw();
    for(int i=0; i<boxCircles.size(); i++){
        boxCircles[i].get()->draw();
    }
}

I don’t know if i am doing it right.
Interaction seems ok. At least there is collisions between shapes and particles.

Now my questions are :

  • how would you manage the triangle and square shapes ? ofPath ? polyline ? what confuses me is that shapes seems to be neither one nor the other but a vector of polyline…

  • i tried to draw the shapes in two different ways :

One with drawing the polyline shape. Seems i need to specify the color and stroke width as it doesn’t grab those properties from the svg ? here is the result using shape.draw();

The other way is by drawing the entire edgeline using edgeline.draw();
Here i an not able to specify the color of the shapes. But even if i could, i don’t know how to set stroke color fore each shape independently ! though the shape is open.

Thanks a lot for your help

this is what i have from a recent project using svg + box2d:

//.h
vector<shared_ptr<ofxBox2dPolygon>> shapes;

//setup

    box2d.init();
    box2d.setFPS(60.0);
    svg.load("shapes.svg");

    for(auto path: svg.getPaths()){
        path.setStrokeWidth(1);
        if(!path.getOutline().empty()){
            shapes.emplace_back(new ofxBox2dPolygon);
            shapes.back()->addVertices(path.getOutline()[0].getVertices());
            shapes.back()->setDensity(0);
            shapes.back()->triangulatePoly();
            shapes.back()->create(box2d.getWorld());
        }
    }

that’s using c++11 syntax so you’ll need to use a nightly build to be able to use it or translate the couple of things that won’t compile uinder older c++

i can’t close the shape nor change it’s stoke or color !
am i doing things wrong ?

.h

ofxBox2d box2d;
vector<shared_ptr<ofxBox2dCircle> > boxCircles;
vector<shared_ptr<ofxBox2dRect> > boxes;
ofxBox2dEdge edgeLine;

ofPath shape;

ofPolyline line;

ofxSVG svg;
vector<ofPath> lines;

.cpp

void ofApp::setup(){
    box2d.init();
    box2d.createBounds();
    //box2d.createGround();
    box2d.setFPS(60.0);
    //box2d.setGravity(ofPoint(0, -1.0, 0));
    
    svg.load("1.svg");
    
    shape = svg.getPathAt(0);
    shape.setStrokeColor(ofColor::yellow);
    shape.setStrokeWidth(2);
    
    edgeLine.addVertexes(shape.getOutline().at(0));
    edgeLine.setPhysics(0.0, 0.5, 0.5);
    edgeLine.create(box2d.getWorld());

}