openframeworks / openFrameworks

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

more vertex points than necessary for curves #1500

Open kylemcdonald opened 12 years ago

kylemcdonald commented 12 years ago

if you generate a curve like this:

vector<ofVec2f> control;
...
ofPath path;
path.curveTo(control.front());
for(int i = 0; i < control.size(); i++) {
  path.curveTo(control[i]);
}
path.curveTo(control.back());
ofPolyline polyline = path.getOutline()[0];
cout << polyline.size() << endl;

the number of points in the polyline are more than necessary. it looks like at each control point, vertices are doubled up -- except for the beginning, where there is only one vertex.

i discovered this while trying to smoothly interpolate along a polyline, and found that the vertices weren't evenly spaced.

c-mendoza commented 10 years ago

I ran into this issue as well when trying out a "thick line" geometry shader. As far as I know this is still happening in the latest builds. Something else to note is that this isn't exactly a "doubling up," since the problem points are VERY close to one another but do not have the exact same coordinates (in my tests they differ by something like 0.0001).

A silly fix would be to modify ofPolyline::curveTo to test whether newly generated points are close to the previously generated point, using ofVec3f::match with a tolerance that would not matter when points are output to the screen (something like 0.01):

void ofPolyline::curveTo( const ofPoint & to, int curveResolution ){

    curveVertices.push_back(to);

    if (curveVertices.size() == 4){

        float x0 = curveVertices[0].x;
        float y0 = curveVertices[0].y;
        float z0 = curveVertices[0].z;
        float x1 = curveVertices[1].x;
        float y1 = curveVertices[1].y;
        float z1 = curveVertices[1].z;
        float x2 = curveVertices[2].x;
        float y2 = curveVertices[2].y;
        float z2 = curveVertices[2].z;
        float x3 = curveVertices[3].x;
        float y3 = curveVertices[3].y;
        float z3 = curveVertices[3].z;

        float t,t2,t3;
        float x,y,z;

        for (int i = 0; i < curveResolution; i++){

            t   =  (float)i / (float)(curveResolution-1);
            t2  = t * t;
            t3  = t2 * t;

            x = 0.5f * ( ( 2.0f * x1 ) +
                        ( -x0 + x2 ) * t +
                        ( 2.0f * x0 - 5.0f * x1 + 4 * x2 - x3 ) * t2 +
                        ( -x0 + 3.0f * x1 - 3.0f * x2 + x3 ) * t3 );

            y = 0.5f * ( ( 2.0f * y1 ) +
                        ( -y0 + y2 ) * t +
                        ( 2.0f * y0 - 5.0f * y1 + 4 * y2 - y3 ) * t2 +
                        ( -y0 + 3.0f * y1 - 3.0f * y2 + y3 ) * t3 );

            z = 0.5f * ( ( 2.0f * z1 ) +
                        ( -z0 + z2 ) * t +
                        ( 2.0f * z0 - 5.0f * z1 + 4 * z2 - z3 ) * t2 +
                        ( -z0 + 3.0f * z1 - 3.0f * z2 + z3 ) * t3 );

            //SILLY FIX HERE:

            //Sometimes this algorithm is generating points that are VERY close to one another
            //This check throws out those uneeded points.

            ofPoint thisPoint = ofPoint(x,y,z);

            if (points.size() > 1) {
                //Check the last point, see if it is close to this one:
                ofPoint *lastPoint = &points.back();
                if (!lastPoint->match(thisPoint, 0.01)) {
                    points.push_back(thisPoint);
                }
            } else {
                points.push_back(thisPoint);

            }
        }
        curveVertices.pop_front();
    }
    flagHasChanged();
}

This is obviously inefficient, but it does fix the problem for now.