public function reduce( $tolerance, $lookAhead=null )
    {
        if ($lookAhead) {
            $this->lookAhead = (int)$lookAhead;
        }

        $key = 0;
        $endPoint = min($this->lookAhead, $this->lastKey());

        do {
            if ( $key + 1 == $endPoint ) {
                if ( $endPoint != $this->lastKey() ) {
                    $key = $endPoint;
                    $endPoint = min($endPoint + $this->lookAhead, $this->lastKey());
                } else {
                    /* Ignore */
                }
            } else {
                $maxIndex = $key + 1;
                $d = $this->shortestDistanceToSegment(
                    $this->points[$maxIndex],
                    $this->points[$key],
                    $this->points[$endPoint]
                );
                $maxD = $d;
                for ( $i = $maxIndex + 1; $i < $endPoint; $i++ ) {
                    $d = $this->shortestDistanceToSegment(
                        $this->points[$i],
                        $this->points[$key],
                        $this->points[$endPoint]
                    );
                    if ( $d > $maxD ) {
                        $maxD = $d;
                        $maxIndex = $i;
                    }
                }
                if ( $maxD > $tolerance ) {
                    $endPoint--;
                } else {
                    for ( $i = $key + 1; $i < $endPoint; $i++ ) {
                        unset($this->points[$i]);
                    }
                    $key = $endPoint;
                    $endPoint = min($endPoint + $this->lookAhead, $this->lastKey());
                }
            }
        } while ( $key < $this->lastKey(-2)
                  || $endPoint != $this->lastKey() );
        return $this->reindex();
    }