2

编辑请参阅下面的评论(问题尚未解决)。任何想尝试我的代码的人都可以在这里进行:http: //tinker.io/e0676

EDIT2我想我已经找到了问题:http ://www.geocomputation.org/1999/076/gc_076.htm将尝试以某种方式解决它......

事情就是这样。如果您有多边形的面积和周长,您可以通过获取 area/(perimeter*perimeter) 的结果来测量多边形与圆的接近程度。我知道如何测量周长:

function getPolySize(arrP){ //the first and last point in arrP is the same!
   var S = 0;
 for(var i=1, l=arrP.length;i<l;i++)
    S += Math.sqrt(Math.pow(arrP[i-1].x-arrP[i].x,2)+Math.pow(arrP[i-1].y-arrP[i].y,2));
return S;
}

和区域:

function getPolyArea(arrP){
var A = 0;
for(var i=0,l=arrP.length-1;i<l;i++)
    A += arrP[i].x*arrP[i+1].y - arrP[i+1].x*arrP[i].y;
A = A/2;    
return Math.abs(A);
}

一切正常,但是如果我制作一个尽可能接近圆形的多边形,我就会开始得到奇怪的结果。我用它来制作圆形多边形:

var arrCircle = [];
function setPixel(x,y){
arrCircle.push({x:x,y:y});
}
function rasterCircle(xCenter, yCenter, radius)
{       
var x, y, r2;
r2 = radius * radius;

for (x = -radius+1; x <= radius; x++){      
    y = Math.floor(Math.sqrt(r2 - x*x) + 0.5);
    setPixel(xCenter + x, yCenter + y);
}
for (x = radius-1; x >= -radius; x--) {
    y = Math.floor(Math.sqrt(r2 - x*x) + 0.5);
    setPixel(xCenter + x, yCenter - y);
}
}
arrCircle.push(arrCircle[0]);

由于半径较大的圆形多边形比半径较小的圆形多边形更接近理想的圆形,我认为圆形越大,面积/(周长*周长)应该越大,但事实并非如此,我不知道为什么。理想圆的“圆度”为 1/4PI (0,07957747154594766788444188168626)。我用(像多边形的圆圈)做了一些测试,这些是我的结果:

radius 10 roundness 0.0760194950578244
radius 20 roundness 0.07542738445429042
radius 30 roundness 0.07549530319982335
radius 40 roundness 0.07472106160782283
radius 50 roundness 0.07490614579701928
radius 60 roundness 0.0750939048274632
radius 70 roundness 0.07502892726254591
radius 80 roundness 0.07512064515249058
radius 90 roundness 0.0752191417813967

那么为什么它应该增加的时候却减少了呢?任何人都可以帮忙吗?

4

3 回答 3

1

那是因为 javascript 像许多其他语言一样存在浮点问题。这是一个已知问题。您最好的解决方案是对数字进行四舍五入。另一种选择是使用大数字。看看这个库的精确度:http: //jsfromhell.com/classes/bignumber

如果您喜欢数学并想更详细地理解它,请查看以下内容:http: //docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

于 2013-03-29T23:21:48.400 回答
1

编辑:我意识到这并不是一个完整的解释,但我确实认为我目前的答案(截至 2013 年 3 月 30 日)提供了一些关于正在(或没有)发生的事情的额外见解。

我开始认为这个总和的极限过程并不是我们想象的那样。极限似乎在 0.075{something.} 左右

我敢打赌,四舍五入的使用与此有关。这对于栅格化非常有意义,但是您使用的公式可以获取未栅格化多边形的确切区域、沿圆边缘的长度等。限制可能会很有趣。

作为比较,我创建了一种通过重复二等分为圆生成多边形的方法。见: http ://tinker.io/e0676/4 (也,下面的代码)

我还修改了您getPolyArea以使用大数字以防万一(对于原始问题,它没有)。

//assumes one end of vector at origin                                                                         
function findNormalizedbisector(x1,y1,x2,y2)
{
    var xnew = (x1 + x2)/2;
    var ynew = (y1 + y2)/2;
    var normalizingfactor = Math.sqrt(xnew*xnew + ynew*ynew);
    xnew = xnew/normalizingfactor;
    ynew = ynew/normalizingfactor;
    return {x:xnew, y:ynew};
}
function rasterCircle2(xCenter, yCenter, radius,levels){
    var begin = [{x:1,y:0},{x:0,y:1},{x:-1,y:0},{x:0,y:-1},{x:1,y:0}];
    var next;
    var begin_length;
    var i,j;
    for (i=0;i<levels; i++){
        next = [begin[0]];
        for(j=1,begin_length = begin.length; j< begin_length; j++){
            var nn1 = begin[j-1];
            var nn2 = begin[j];
            next.push(findNormalizedbisector(nn1.x,nn1.y,nn2.x,nn2.y));
            next.push(nn2);
        }
        begin = next;
    }
    for(i=0,begin_length = begin.length; i< begin_length; i++){
        var nn3 = begin[i];
        nn3.x = nn3.x*radius + xCenter;
        nn3.y = nn3.y*radius + yCenter;
    }
    return begin;
}
for(var i=1;i<10;i++){
    var arr = rasterCircle2(200,200,800,i);
    var round = getRoundness(arr);
    document.write('levels_of_bisection: '+i+' num of points: '+arr.length+' roundness: '+round+'<br />');

}

这个加上我的mods到你原来的输出如下。请注意,通过二分法,我们终于看到了我们期望的数字。还要注意使用半径为 8000 的(大部分)原始方法的输出

levels_of_bisection: 1 num of points: 9 roundness: 0.0754441738241592276887245725443626784735
levels_of_bisection: 2 num of points: 17 roundness: 0.0785521795644663802398108421050698627987
levels_of_bisection: 3 num of points: 33 roundness: 0.0793216436531942231002943881950341480514
levels_of_bisection: 4 num of points: 65 roundness: 0.0795135454101061996101090797300452576319
levels_of_bisection: 5 num of points: 129 roundness: 0.0795614919376626996487018238437628627337
levels_of_bisection: 6 num of points: 257 roundness: 0.0795734767642052437694275988417572320135
levels_of_bisection: 7 num of points: 513 roundness: 0.0795764728580322174704427590361452409546
levels_of_bisection: 8 num of points: 1025 roundness: 0.0795772218744387817478897891643047512062
levels_of_bisection: 9 num of points: 2049 roundness: 0.0795774091280998583674859904802485345865
radius: 8000 num of points: 32001 roundness: 0.0751003307245799769095159405113677586659
于 2013-03-31T02:08:41.690 回答
0

我尝试按照 Jayc 的建议进行操作,但这仅在我不将其与 Big numbers 一起使用且仅更改最后三位小数时才有效。我的数字在小数点后第三位已经不正确了。

我也尝试了我们上面建议的大数字,但这也不起作用。我使用了 DP = 40(小数位)的https://github.com/MikeMcl/big.js 。这个库可以做 sqrt 不像上面建议的那样(上面也不能做 pow(0.5) )。

所以这里是结果:

radius 10 roundness 0.0760194950578243423134496712198170723197 
radius 20 roundness 0.0754273844542903459173216205506653687584 
radius 30 roundness 0.0754953031998234468551935482682038382823 
radius 40 roundness 0.0747210616078230319421955905769628317386 
radius 50 roundness 0.0749061457970194359965013537625645613175 
radius 60 roundness 0.0750939048274633950478066316279606244677 
radius 70 roundness 0.0750289272625461826452420199713700795491 
radius 80 roundness 0.0751206451524908473183103264150172570221 
radius 90 roundness 0.0752191417813970247297347505177938519628 

和新代码:

var S = new Big(0);
var arr = [];
for(var i=1, l=arrP.length;i<l;i++){       
    var add = Math.pow(arrP[i-1].x-arrP[i].x,2)+Math.pow(arrP[i-1].y-arrP[i].y,2);      
    var x = new Big(add);       
    x = x.sqrt();
    arr.push(x);
    S = S.plus(x);
}

arr.sort(function(a,b){return a-b});
var c = new Big(0);
for(var i=0;i<arr.length;i++){
    var y = arr[i].minus(c);
    var t = S.plus(y);
    c = t.minus(S).minus(y);
    S = t;      
}

我不禁认为浮点不是这里的问题。我尝试了 1000(!)小数位的测试,并得到了与上面所见完全相同的数字(仅长一点,但前 40 位数字相同)。

还有其他问题,但是什么?

于 2013-03-30T16:32:44.650 回答