Get ofPath bounding box


#1

I use this function to determine the bounding box of an ofPath if it’s not in command mode. Does this make sense? Is there a quicker method?

Also, yeah, getting the arc is possibly mathematically incorrect, potential shame on me. what do you do there? calculate for both radii and then interpolate with … no wait, it should be as simple as knowing which radius belongs to which angle, right?

ofRectangle getBoundingBoxOfPath( ofPath * path ){
ofRectangle rec;
rec.set(FLT_MAX, FLT_MAX, FLT_MIN, FLT_MIN);
for(int c = 0; c < path->getCommands().size(); c++){
	unsigned int points = 0;
	unsigned int k;
	switch (path->getCommands()[c].type) {
        case ofPath::Command::lineTo:
        case ofPath::Command::curveTo:
            points = 1;
            break;
        case ofPath::Command::arc:
            points = 2;
            break;
        case ofPath::Command::bezierTo:
        case ofPath::Command::quadBezierTo:
            points = 3;
            break;
        case ofPath::Command::moveTo:
        case ofPath::Command::close:
            points = 0;
            break;
        default:
            assert(0);
	}
    
    if(points == 1 || points == 3){
        
        rec.x = min(rec.x, path->getCommands()[c].to.x);
        rec.width = max(rec.width, path->getCommands()[c].to.x);
        rec.y = min(rec.y, path->getCommands()[c].to.y);
        rec.height = max(rec.height, path->getCommands()[c].to.y);
        
        if(points == 3){
            rec.x = min(min(rec.x, path->getCommands()[c].cp1.x),path->getCommands()[c].cp2.x);
            rec.width = max(max(rec.width, path->getCommands()[c].cp1.x),path->getCommands()[c].cp2.x);
            rec.y = min(min(rec.y, path->getCommands()[c].cp1.y),path->getCommands()[c].cp2.y);
            rec.height = max(max(rec.height, path->getCommands()[c].cp1.y),path->getCommands()[c].cp2.y);
        }
	} else if (points == 2) {
        // WARNING: no idea if the following is mathematically correct, since we have two different radii
        float h1 = sin(path->getCommands()[c].angleBegin) * path->getCommands()[c].radiusX;
        float w1 = sqrt((h1*h1) - (path->getCommands()[c].radiusX*path->getCommands()[c].radiusX));
        
        float h2 = sin(path->getCommands()[c].angleEnd) * path->getCommands()[c].radiusY;
        float w2 = sqrt((h2*h2) - (path->getCommands()[c].radiusY*path->getCommands()[c].radiusY));
        
        rec.x = min(min(rec.x, path->getCommands()[c].cp1.x+w1),path->getCommands()[c].cp1.x+w2);
        rec.width = max(max(rec.x, path->getCommands()[c].cp1.x+w1),path->getCommands()[c].cp1.x+w2);
        rec.y = min(min(rec.x, path->getCommands()[c].cp1.y+h1),path->getCommands()[c].cp1.y+h2);
        rec.height = max(max(rec.x, path->getCommands()[c].cp1.y+h1),path->getCommands()[c].cp1.y+h2);
    }
}
rec.width -= rec.x;
rec.height -= rec.y;
return rec;

}

btw, i had a small formatting error in this post, and i can’t edit it without adding this sentence here because “Body is too similar to what you recently posted”. Shouldn’t it be possible to change little things? Sometimes the smallest details make the difference :slight_smile:


#2

i think that won’t give a correct bounding box for curves and arcs. i guess the easiest would be to get the outlines as polylines and use the same algorithm you are using there but going through the points of each polyline


#3

you are correct, the algorithm failes at curves and arcs.

the disappointing result:

comparison with ofPolyline.getBoundingBox():

seems like the easiest way to go after all, thx!


#4

This works for me:

  ofRectangle getBoundingBoxOfPath(ofPath &path) {
    ofRectangle rect;
    for (int i=0; i<path.getOutline().size(); i++) {
      ofRectangle b = path.getOutline().at(i).getBoundingBox();
      if (i==0) rect = b;
      else rect.growToInclude(b);
    }
    return rect;
  }

#5

When PolyWindingMode isn’t set to OF_POLY_WINDING_ODD, I couldn’t get correct getOutline and bounding box.

So i set polyWindingMode to OF_POLY_WINDING_ODD to getBoundingBox.