简体   繁体   English

计算贝塞尔曲线下的面积

[英]Calculate area under Bezier curve

I'm trying to find a straightforward answer to this question, but the answers I find are often extremely conveluded, or require logic more complicated than what is required. 我正在尝试找到该问题的直接答案,但是我发现的答案通常非常复杂,或者需要比所需逻辑更复杂的逻辑。 My question is based on the following example: 我的问题基于以下示例:

Let's say I've got a series of points. 假设我有一系列观点。 They are all very tame and predictable, in that they always take on a mathematical curve pattern... (They always start bottom-left and end top-right) 它们都是非常温顺且可预测的,因为它们始终采用数学曲线模式... (它们始终从左下开始,从右上结束)

在此处输入图片说明

How would I determine the area under this curve in PHP? 如何确定PHP中此曲线下的面积?

Note that I attempt to replicate this example in Javascript using Canvas but failed miserably (using examples like this ) 请注意,我尝试使用Canvas在Javascript中复制此示例,但不幸失败(使用类似这样的示例)

<?php
    //Example requires Imagick
    $width =  800;
    $height = 200;
    $img = new Imagick();
    $img->newImage( $width, $height, new ImagickPixel( 'transparent' ) );
    $draw = new ImagickDraw();
    $draw->setStrokeColor( new ImagickPixel( 'red' ) );
    $draw->setStrokeWidth(4 );
    $draw->setFillColor( new ImagickPixel( 'transparent' ) );
    $points = array
    ( 
        array( 'x' => 0, 'y' => 200 ), 
        array( 'x' => 100, 'y' => 0 ), 
        array( 'x' => 200, 'y' => 200 ), 
        array( 'x' => 300, 'y' => 0 ),
        array( 'x' => 400, 'y' => 10 ), 
        array( 'x' => 500, 'y' => 0 )
    );
    $draw->bezier($points);
    $img->drawImage( $draw );
    $img->setImageFormat( "png" );
    header( "Content-Type: image/png" );
    echo $img;
?>

I understand this question may take a few iterations for me to ask... I would have posted a JSFiddle to back up this example and make it easier to work with, however I could not convert it for use with js/bezierCurveTo, so if a user could help with that it would also be a very useful substitute 我知道这个问题可能要花一些迭代的时间问我。。。我会发布一个JSFiddle来备份此示例并使其更易于使用,但是我无法将其转换为与js / bezierCurveTo一起使用,所以如果用户可以帮助它,它也是一个非常有用的替代品

MBo's solution will give an exact answer, you can also try to use a numerical solution. MBo的解决方案将给出确切的答案,您也可以尝试使用数值解决方案。

As your curve is always increasing in the x direction we can slice it up in the x-direction and approximate the area of each slice. 由于您的曲线总是在x方向上增加,因此我们可以在x方向上对其进行切片,并近似于每个切片的面积。 For example if we have four points on the curve (x0,y0), (x1,y1), (x2,y2), (x3,y3) we find the area of the first slice using 例如,如果曲线上有四个点(x0,y0),(x1,y1),(x2,y2),(x3,y3),则使用

(x1-x0)*(y0+y1)/2

this is the area of a trapezium. 这是梯形的区域。 Do the same for each pair of points and add them up. 对每对点都做同样的事情,并将它们加起来。 If your x coords are evenly spaced this gives the trapezium rule which we can simplify. 如果您的x坐标均匀分布,则将给出梯形规则,我们可以简化该规则。 We can assume that here as we are using Bezier curves. 我们可以假设这里使用的是贝塞尔曲线。

Things are a bit more tricky if we have Bezier curves as we don't actually know the points on the curve. 如果我们有Bezier曲线,则事情会有些棘手,因为我们实际上并不知道曲线上的点。 All is not lost as MBo has given the formula for the points MBo给出了积分的公式,一切都没有丢失

X(t) = P[0].X*(1-t)^3+3*P[1].X*t*(1-t)^2+3*P[2].X*t^2*(1-t)+P[3].X*t^3
Y(t) = P[0].Y*(1-t)^3+3*P[1].Y*t*(1-t)^2+3*P[2].Y*t^2*(1-t)+P[3].Y*t^3

P[0].X is the x coord of your first control point, P[0].Y is the Y value, etc. In code you need to use P [0] .X是第一个控制点的x坐标,P [0] .Y是Y值,等等。在代码中,您需要使用

x = P[0].X*(1-t)*(1-t)*(1-t)+3*P[1].X*t*(1-t)*(1-t)+3*P[2].X*t*t*(1-t)+P[3].X*t*t*t;
y = P[0].Y*(1-t)*(1-t)*(1-t)+3*P[1].Y*t*(1-t)*(1-t)+3*P[2].Y*t*t*(1-t)+P[3].Y*t*t*t;

which uses multiplication rather than powers. 它使用乘法而不是幂。 Use a number of values of t between 0 and 1 to find points on the curve and then find the slices. 使用0到1之间的多个t值来找到曲线上的点,然后找到切片。

I've put a javascript fiddle which puts this all together http://jsfiddle.net/SalixAlba/QQnvm/ 我放了一个JavaScript小提琴,将所有这些放在一起http://jsfiddle.net/SalixAlba/QQnvm/

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

// The control points
var P = [{X:  13, Y: 224 }, 
     {X: 150, Y: 100 }, 
     {X: 251, Y: 224 }, 
     {X: 341, Y:  96 }, ];

ctx.lineWidth = 6;
ctx.strokeStyle = "#333";
ctx.beginPath();
ctx.moveTo(P[0].X, P[0].Y);
ctx.bezierCurveTo(P[1].X, P[1].Y, P[2].X, P[2].Y, P[3].X, P[3].Y);
ctx.stroke();

// draw the control polygon
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(P[0].X, P[0].Y);
ctx.lineTo(P[1].X, P[1].Y);
ctx.lineTo(P[2].X, P[2].Y);
ctx.lineTo(P[3].X, P[3].Y);
ctx.stroke();

function findarea(n) {
ctx.lineWidth = 3;
ctx.strokeStyle = "#f00";
ctx.beginPath();

var nSteps = n - 1;
var x = [P[0].X];
var y = [P[0].Y];
ctx.moveTo(x[0], y[0]);

var area = 0.0;
for (var i = 1; i <= nSteps; ++i) {
    var t = i / nSteps;
    x[i] = P[0].X*(1-t)*(1-t)*(1-t)+3*P[1].X*t*(1-t)*(1-t)+3*P[2].X*t*t*(1-t)+P[3].X*t*t*t;
    y[i] = P[0].Y*(1-t)*(1-t)*(1-t)+3*P[1].Y*t*(1-t)*(1-t)+3*P[2].Y*t*t*(1-t)+P[3].Y*t*t*t;
    ctx.lineTo(x[i], y[i]);

    area += (x[i] - x[i-1]) * (y[i-1] + y[i]) / 2;

    if(x[i]<x[i-1]) alert("Not strictly increasing in x, area will be incorrect");
}
ctx.stroke();
$("#area").val(area);
}

$("#goBut").click(function () {
    findarea($("#nPts").val());
});

You can calculate area under parametric curve using formula 您可以使用公式计算参数曲线下的面积

A = Integral[t0..t1] (y(t)*x'(t)*dt)

For cubic Bezier: (I don't sure what kind of Bezier curve you are using) 对于三次方贝塞尔曲线:(我不确定您使用的是哪种贝塞尔曲线)

Area = Integral[0..1](y(t)*x'(t)*dt)=
Integral[0..1](
(P[0].Y*(1-t)^3+3*P[1].Y*t*(1-t)^2+3*P[2].Y*t^2*(1-t)+P[3].Y*t^3)*
(P[0].X*(1-t)^3+3*P[1].X*t*(1-t)^2+3*P[2].X*t^2*(1-t)+P[3].X*t^3)'*
dt)

You have to expand the brackets, differentiate the second line expression, multiply expressions, and integrate the result 您必须展开方括号,区分第二行表达式,将表达式相乘并积分结果

Maple work (it is hard to copy text without distortions): 枫木作品(很难复制没有扭曲的文本): 在此处输入图片说明 Note that some expressions are used many times 请注意,某些表达式已多次使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM