如何计算贝塞尔曲线的面积

如何计算贝塞尔曲线的面积

本文介绍了如何计算贝塞尔曲线的面积?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下描述SVG三次贝塞尔曲线的路径(例如):M300,140C300,40,500,40,500,140,
并假设连接端点300,140到500,140的直线(关闭下面的区域)曲线),是否可以计算如此封闭的区域?



有人可以建议一个公式(或JavaScript)来完成这个吗?

解决方案

和和。

  //计算SVG多边形/折线的面积
函数polyArea(poly){
var area = 0,pts = poly.points,len = pts。东西的个数;
for(var i = 0; i< len; ++ i){
var p1 = pts.getItem(i),p2 = pts.getItem((i + len-1)%len) ;
area + =(p2.x + p1.x)*(p2.y-p1.y);
}
返回Math.abs(area / 2);
}

//创建一个< polygon> SVG的近似<路径>
函数pathToPolygon(路径,样本){
if(!samples)samples = 0;
var doc = path.ownerDocument;
var poly = doc.createElementNS('http://www.w3.org/2000/svg','polygon');

//将所有路径段放入队列
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 + = sx; 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< len; ++ i)addSegmentPoint(segs [i]);
for(var i = 0,len = points.length; i< len; ++ i)points [i] = points [i] .join(',');
poly.setAttribute('points',points.join(''));
返回poly;
}


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 300,140 to 500,140 (closing the area under the curve), is it possible to calculate the area so enclosed?

Can anyone suggest a formula (or JavaScript) to accomplish this?

解决方案

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

Interactive Demo: Area of Path via Subdivision

                     

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 <path> 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 <polygon> 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<segments;i++){
      pts[i] = ptWithLength(p1.d + step*i);
    }
    pts.push(p2);
    if (polyArea(pts)<=threshold) return [p1,p2];
    else {
      var result = [];
      for (var i=1;i<pts.length;++i){
        var mids = subdivide(pts[i-1], pts[i]);
        mids.pop(); // We'll get the last point as the start of the next pair
        result = result.concat(mids)
      }
      result.push(p2);
      return result;
    }
  }

  // Calculate the area of an polygon represented by an array of points
  function polyArea(points){
    var p1,p2;
    for(var area=0,len=points.length,i=0;i<len;++i){
      p1 = points[i];
      p2 = points[(i-1+len)%len]; // Previous point, with wraparound
      area += (p2.x+p1.x) * (p2.y-p1.y);
    }
    return Math.abs(area/2);
  }
}
// Return the area for an SVG <polygon> or <polyline>
// Self-crossing polys reduce the effective 'area'
function polyArea(poly){
  var area=0,pts=poly.points,len=pts.numberOfItems;
  for(var i=0;i<len;++i){
    var p1 = pts.getItem(i), p2=pts.getItem((i+-1+len)%len);
    area += (p2.x+p1.x) * (p2.y-p1.y);
  }
  return Math.abs(area/2);
}


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

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

                 

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<len;++i){
    var p1 = pts.getItem(i), p2=pts.getItem((i+len-1)%len);
    area += (p2.x+p1.x) * (p2.y-p1.y);
  }
  return Math.abs(area/2);
}

// Create a <polygon> approximation for an SVG <path>
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<len;++i) addSegmentPoint(segs[i]);
  for (var i=0,len=points.length;i<len;++i) points[i] = points[i].join(',');
  poly.setAttribute('points',points.join(' '));
  return poly;
}

这篇关于如何计算贝塞尔曲线的面积?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 15:52