如何计算PHP中一行的点数?

时间:2011-10-17 19:26:17

标签: php math geometry

如果这个过于简单,我道歉,但我是数学专业最可能的事情,而且我无法将抽象公式简化为可行的代码。我知道一条线的公式,但把它变成代码让我头晕目眩。并强调我的代码调试器。

给定一个2D网格坐标系,我需要能够指定一个起点X1,Y1和一个终点X2,Y2,并直接在这两个点之间的一条直线上计算所有网格单元的列表。

所以如果......

X1,Y1 = 3,3
X2,Y2 = 0,5

我想计算一个点数组

3,3
2,4
1,4
0,5

或类似的东西。能够按顺序列出这些点也很重要 - 如上所述,我从原点X,Y开始,然后朝目的地X,Y方向移动。

(不,这不是作业 - 我已经看到了这里要求了很多其他的数学问题,所以我会先把它弄出去。也许如果我把它作为家庭作业25年前我现在不需要问!)

我确实发现PHP Find Coordinates between two points似乎在讨论解决方案,但评论表明“已接受”的答案并不完整。

非常感谢。

5 个答案:

答案 0 :(得分:4)

听起来你最好的选择可能是Bresenham's algorithm for drawing a line,除了不是绘制你将捕获x,y值的点。

答案 1 :(得分:1)

我假设您需要整数坐标,因为这是您在示例中列出的内容。但请注意,对于任何一组(x1,y1)和(x2,y2),情况不一定如此。我的答案只给你全数x坐标。

我会使用线性方程的两点形式。 yi =(y2-y1)/(x2-x1)*(xi-x1)+ y1 其中(xi,yi)是您要寻找的点。

for ($xi=$x1; $xi<$x2; $xi++) {
  $yi = ($y2-$y1)/($x2-$x1)*($xi-$x1) + $y1
  echo $xi + "," + $yi
}

在运行上述代码之前,请确保您拥有$x1 < $x2

当您在两个任意点(x1,y1)和(x2,y2)之间绘制一条直线并且想要输出与该直线相交的正方形(网格单元格)列时,会出现更复杂的情况。

答案 2 :(得分:1)

因此,对于更多细节,这里是一个PHP函数,它将始终返回以第一个数组元素作为原点而最后一个作为目标的点。这是经过测试和运作的,是http://alex.moutonking.com/wordpress/?p=44的改编版。

function bresenham($x1, $y1, $x2, $y2, $guaranteeEndPoint=true) {
    $xBegin = $x1;
    $yBegin = $y1;
    $xEnd = $x2;
    $yEnd = $y2;
    $dots = array();

    $steep = abs($y2 - $y1) &gt; abs($x2 - $x1);

    if ($steep) {
        $tmp = $x1;
        $x1 = $y1;
        $y1 = $tmp;
        $tmp = $x2;
        $x2 = $y2;
        $y2 = $tmp;
    }

    if ($x1 > $x2) {
        $tmp = $x1;
        $x1 = $x2;
        $x2 = $tmp;
        $tmp = $y1;
        $y1 = $y2;
        $y2 = $tmp;
    }

    $deltax = floor($x2 - $x1);
    $deltay = floor(abs($y2 - $y1));
    $error = 0;
    $deltaerr = $deltay / $deltax;
    $y = $y1;
    $ystep = ($y1 < $y2) ? 1 : -1;

    for ($x = $x1; $x < $x2; $x++) {
        $dots[] = $steep ? array($y, $x) : array($x, $y);       
        $error += $deltaerr;        
        if ($error >= 0.5) {
            $y += $ystep;
            $error -= 1;
        }
    } 

    if ($guaranteeEndPoint) {
    if ((($xEnd - $x) * ($xEnd - $x) + ($yEnd - $y) * ($yEnd - $y)) < (($xBegin - $x) * ($xBegin - $x) + ($yBegin - $y) * ($yBegin - $y))) {
        $dots[] = array($xEnd, $yEnd);
    } else 
        $dots[] = array($xBegin, $yBegin);
    }

    if ($dots[0][0] != $xBegin and $dots[0][1] != $yBegin) {
        return array_reverse($dots);        
    } else {
        return $dots;
    }
}

答案 3 :(得分:0)

我不知道这是特别优雅的,但是我会这样做:

function getLinePoints( $startPoint, $endPoint ){
    $totalSteps = max( abs( $startPoint[0] - $endPoint[0] ), abs( $startPoint[1] - $endPoint[1] ) );
    if ( $totalSteps == 0 ){
      return $startPoint;
    }
    $xStep = ( $endPoint[0] - $startPoint[0] ) / $totalSteps;
    $yStep = ( $endPoint[1] - $startPoint[1] ) / $totalSteps;

    $points[] = $currentPoint = $startPoint;
    for( $step = 0; $step < $totalSteps; $step++ ){
        $currentPoint[0] += $xStep;
        $currentPoint[1] += $yStep;
        $points[] = array( round( $currentPoint[0], 0 ), round( $currentPoint[1], 0 ) );
    }
    return $points;
}

$pointA = array( 3, 3 );
$pointB = array( 0, 5 );
$points = getLinePoints( $pointA, $pointB );

这需要执行以下步骤:

  1. 获取水平或垂直移动所需的总点数。
  2. 计算每一步水平或垂直移动的距离。
  3. 构造一个点数组,其坐标四舍五入为整数。
  4. 返回值应为:

    Array(
        Array( 3, 3 ),
        Array( 2, 4 ),
        Array( 1, 4 ),
        Array( 0, 5 )
    )
    

答案 4 :(得分:0)

看起来你正在寻找插值方法,检查一下:http://paulbourke.net/miscellaneous/interpolation/(你需要的是线性插值)