How can I calculate the area of a bezier curve?

前端 未结 6 1638
孤独总比滥情好
孤独总比滥情好 2020-12-08 10:49

Given the following path (for example) which describes a SVG cubic bezier curve: \"M300,140C300,40,500,40,500,140\", and assuming a straight line connecting the end points 3

6条回答
  •  佛祖请我去吃肉
    2020-12-08 11:18

    Convert the path to a polygon of arbitrary precision, and then calculate the area of the polygon.

    Interactive Demo: Area of Path via Subdivision

                          Screenshot of Demo

    At its core the above demo uses functions for adaptively subdividing path into a polygon and computing the area of a polygon:

    // path:      an SVG  element
    // threshold: a 'close-enough' limit (ignore subdivisions with area less than this)
    // segments:  (optional) how many segments to subdivisions to create at each level
    // returns:   a new SVG  element
    function pathToPolygonViaSubdivision(path,threshold,segments){
      if (!threshold) threshold = 0.0001; // Get really, really close
      if (!segments)  segments = 3;       // 2 segments creates 0-area triangles
    
      var points = subdivide( ptWithLength(0), ptWithLength( path.getTotalLength() ) );
      for (var i=points.length;i--;) points[i] = [points[i].x,points[i].y];
    
      var doc  = path.ownerDocument;
      var poly = doc.createElementNS('http://www.w3.org/2000/svg','polygon');
      poly.setAttribute('points',points.join(' '));
      return poly;
    
      // Record the distance along the path with the point for later reference
      function ptWithLength(d) {
        var pt = path.getPointAtLength(d); pt.d = d; return pt;
      }
    
      // Create segments evenly spaced between two points on the path.
      // If the area of the result is less than the threshold return the endpoints.
      // Otherwise, keep the intermediary points and subdivide each consecutive pair.
      function subdivide(p1,p2){
        var pts=[p1];
        for (var i=1,step=(p2.d-p1.d)/segments;i
    // Return the area for an SVG  or 
    // Self-crossing polys reduce the effective 'area'
    function polyArea(poly){
      var area=0,pts=poly.points,len=pts.numberOfItems;
      for(var i=0;i

    Following is the original answer, which uses a different (non-adaptive) technique for converting the to a .

    Interactive Demo: http://phrogz.net/svg/area_of_path.xhtml

                      Screenshot of Demo

    At its core the above demo uses functions for approximating a path with a polygon and computing the area of a polygon.

    // Calculate the area of an SVG polygon/polyline
    function polyArea(poly){
      var area=0,pts=poly.points,len=pts.numberOfItems;
      for(var i=0;i approximation for an SVG 
    function pathToPolygon(path,samples){
      if (!samples) samples = 0;
      var doc = path.ownerDocument;
      var poly = doc.createElementNS('http://www.w3.org/2000/svg','polygon');
    
      // Put all path segments in a queue
      for (var segs=[],s=path.pathSegList,i=s.numberOfItems-1;i>=0;--i)
        segs[i] = s.getItem(i);
      var segments = segs.concat();
    
      var seg,lastSeg,points=[],x,y;
      var addSegmentPoint = function(s){
        if (s.pathSegType == SVGPathSeg.PATHSEG_CLOSEPATH){
    
        }else{
          if (s.pathSegType%2==1 && s.pathSegType>1){
            x+=s.x; y+=s.y;
          }else{
            x=s.x; y=s.y;
          }          
          var last = points[points.length-1];
          if (!last || x!=last[0] || y!=last[1]) points.push([x,y]);
        }
      };
      for (var d=0,len=path.getTotalLength(),step=len/samples;d<=len;d+=step){
        var seg = segments[path.getPathSegAtLength(d)];
        var pt  = path.getPointAtLength(d);
        if (seg != lastSeg){
          lastSeg = seg;
          while (segs.length && segs[0]!=seg) addSegmentPoint( segs.shift() );
        }
        var last = points[points.length-1];
        if (!last || pt.x!=last[0] || pt.y!=last[1]) points.push([pt.x,pt.y]);
      }
      for (var i=0,len=segs.length;i

提交回复
热议问题