openframeworks / openFrameworks

openFrameworks is a community-developed cross platform toolkit for creative coding in C++.
http://openframeworks.cc
Other
9.96k stars 2.55k forks source link

ofPath isn't able to switch drawing modes #1575

Open damian0815 opened 12 years ago

damian0815 commented 12 years ago

as per email discussion beginning http://dev.openframeworks.cc/htdig.cgi/of-dev-openframeworks.cc/2012-April/004332.html

i'd like to propose a couple of changes to the way ofPath works around handling Catmull-Rom and Bezier segments.

i'm calling this code:

ofPath path;
path.moveTo( 100, 100 );
path.lineTo( 150, 100 );
path.curveTo( 200, 150 );
path.lineTo( 200, 200 );
path.draw();

when i read this i'm visualizing a horizontal line segment and a vertical line segment with a curve smoothly connecting them, something like this (no.1): no.1

or at least (though less desirable), this (no.2): no.2

what i actually get is this (no.3) no.3

whether it's a bug or not, i think no.3 is wrong. i asked for a curve! where's my curve? also why is my 3rd point being completely ignored?

possible objections to this line of thinking (aka, what Arturo said):

(there's an analogous case here for bezierTo: if i'm coming out of or joining to a straight line segment or another curve i would like an option for my bezier handles to be calculated automatically; similarly it'd be nice to have an option to automatically mirror a previous bezier segment's handle for the first control point to bezierTo, in order to avoid making a corner.)

so, what is the correct behaviour with this code?

path.moveTo( 100, 100 );
path.lineTo( 150, 100 );
path.curveTo( 200, 150 );
path.lineTo( 200, 200 );

to me, it's something like no.1, a horizontal line segment and a vertical line segment with a curve smoothly connecting them.

does anyone else expect something different?

if not, let's make ofPath work this way!

notes:

source to generate no.3:

vector<ofPoint> points;
points.push_back( ofPoint( 100, 100 ) );
points.push_back( ofPoint( 150, 100 ) );
points.push_back( ofPoint( 200, 150 ) );
points.push_back( ofPoint( 200, 200 ) );

ofNoFill();
ofSetColor( 128, 128, 128 );
for ( int i=0; i<points.size(); i++ )
    ofCircle( points[i], 5 );

ofPath path;
path.moveTo( points[0] );
path.lineTo( points[1] );
path.curveTo( points[2] );
path.lineTo( points[3] );
path.setColor( ofColor( 255, 255, 255 ) );
path.setFilled(false);
path.draw();

for image no.1 substitute:

path.moveTo( points[0] );
path.lineTo( points[1] );
path.bezierTo( ofPoint( 175, 100 ), ofPoint( 200, 125 ), points[2] );
path.curveTo( points[2] );
path.lineTo( points[3] );

(there are other viable locations for the bezier control handles here, but i like the way this one looks. it's easy to calculate mathematically: cast a ray from [1] in the same direction as the [0]->[1] line segment, and find the point along the ray at (say) 1/3 of the distance between [1] and [2]; this is your first control point. do something similar for the second control point.)

image no.2 is generated by

path.moveTo( points[0] );
path.lineTo( points[1] );
path.curveTo( points[0] );
path.curveTo( points[1] );
path.curveTo( points[2] );
path.curveTo( points[3] );
path.lineTo( points[3] );

this is pretty ugly code and unfortunately it creates corners at points[1] and points[2] which isn't correct in my opinion.

damian0815 commented 12 years ago

wow that was really long.

danomatika commented 12 years ago

"it doesn't look like i'm doing anything wrong. i expect it to work, and when it doesn't i become confused and angry"

I think this applies to all programming ...

kylemcdonald commented 9 years ago

something has fundamentally changed about ofPath or there is a bug right now that is keeping me from drawing non-filled ofPaths -- but the question is relevant and needs to be looked into to create a more natural API i think.

#include "ofMain.h"

class ofApp : public ofBaseApp {
public:
    void setup() {
    }
    void draw() {
        ofBackground(0);
        ofPath path;
        path.moveTo( 100, 100 );
        path.lineTo( 150, 100 );
        path.curveTo( 200, 150 );
        path.lineTo( 200, 200 );
        path.setColor(ofColor::white);
//        path.setFilled(false);
        path.draw();
    }
};
int main() {
    ofSetupOpenGL(300, 300, OF_WINDOW);
    ofRunApp(new ofApp());
}

screen shot 2015-01-17 at 17 33 44