mjaschen / phpgeo

Simple Yet Powerful Geo Library for PHP
https://phpgeo.marcusjaschen.de
MIT License
1.55k stars 195 forks source link

Line::intersectsLine() is buggy #96

Open vlad-vinogradov opened 1 year ago

vlad-vinogradov commented 1 year ago

Hello, Unfortunately, the Line::intersectsLine() method doesn't always work correctly. Try this test:

<?php
declare(strict_types=1);
require 'vendor/autoload.php';

use Location\Coordinate;
use Location\Line;

$line1 = new Line(
    new Coordinate(0.0, 0.0),
    new Coordinate(0.0, 2.0)
);
$line2 = new Line(
    new Coordinate(2.0, 2.0),
    new Coordinate(0.0, 10.0)
);
if ($line1->intersectsLine($line2)) {
    echo 'Line::intersectsLine() is buggy!'.PHP_EOL;
}
mjaschen commented 1 year ago

Added a test for this issue: https://github.com/mjaschen/phpgeo/compare/master...fix/96

@nilshoerrmann It seems that there's a bug when checking for line intersection for some edge cases – do you have an idea for a fix/workaround?

nilshoerrmann commented 1 year ago

I'll have a look at this over the next days.

nilshoerrmann commented 1 year ago

From a quick look at the source, in intersectsLine() we have these conditions:

// the lines are collinear or touch
if (
    in_array(self::ORIENTATION_COLLINEAR, $orientation, true)
    && (new Intersection())->intersects($this, $line, false)
) {
    return true;
}

This only works if all points are collinear but fails if this is only true for three points (as in the example). So we would either have to switch to high precision for all calculations – (new Intersection())->intersects($this, $line, true) – or we would have to add a more precise condition that distinguises between three collinear points (setting precision to true) and four collinear points (settings precision to false).