Esempio n. 1
0
function pbuild_make_link(&$p2p_links, $ends, $dist = FALSE)
{
    global $wpdb;
    $rec = reset($ends);
    $name = clb_val('', $rec, RF_NODES_TYPE) . ': ' . clb_val('', $rec, RF_NODES_NAME);
    $lat1 = clb_val(0, $rec, 'lat');
    $lng1 = clb_val(0, $rec, 'lng');
    $pnum1 = clb_val(0, $rec, RF_LINKS_KEY);
    $rec = next($ends);
    $name .= clb_val('', $rec, RF_NODES_TYPE) . ': ' . clb_val('', $rec, RF_NODES_NAME);
    $lat2 = clb_val(0, $rec, 'lat');
    $lng2 = clb_val(0, $rec, 'lng');
    $pnum2 = clb_val(0, $rec, RF_LINKS_KEY);
    //checking for existing links, and specifically any existing walk link
    $linkpnum = '';
    $makelink = TRUE;
    if (isset($p2p_links['nodes'][$pnum1]) && isset($p2p_links['nodes'][$pnum2])) {
        //get the list of link_pnums for both nodes and intersect to see if they are already connected
        $connections = array_intersect(explode(',', $p2p_links['nodes'][$pnum1]), explode(',', $p2p_links['nodes'][$pnum2]));
        $makelink = count($connections) <= 0;
        //dont make a link if there is already a direct link
        //if there are links see if one of them is a walk link in which case we may want to update it if the ends have moved.
        foreach ($connections as $ref) {
            if (isset($p2p_links['links'][$ref]['ptype']) && $p2p_links['links'][$ref]['ptype'] == 'walk') {
                $linkpnum = $ref;
                $makelink = TRUE;
                //comment this out if dont want to update walk links
                if (isset($p2p_links['links'][$ref]['pt_count']) && $p2p_links['links'][$ref]['pt_count'] > 2) {
                    $makelink = FALSE;
                }
                //if the walk link has more than 2 points then
                break;
            }
        }
        if (count($connections) > 1 && $linkpnum) {
            qlog(__LINE__, 'walk link and other link types', $pnum1, $pnum2, $connections);
        }
    }
    /*
    	$p2p_links may not include existing "walk" interchanges if there were no routes involving the stops
    	but to prevent creating duplicates do a search and do nothing if a walk exists
    */
    if ($makelink && !$linkpnum) {
        $pair = clb_join(array($pnum1, $pnum2), TRUE);
        $query = 'SELECT ' . RF_LINKS_KEY . ' FROM ' . RF_LINKS_FROM . ' WHERE ' . RF_LINKS_TYPE . '="walk" AND ' . RF_LINKS_END1 . ' IN ' . $pair . ' AND ' . RF_LINKS_END2 . ' IN ' . $pair;
        $check = $wpdb->get_results($query, ARRAY_A);
        if (is_array($check) && clb_val('', reset($check), RF_LINKS_KEY)) {
            $makelink = FALSE;
        }
    }
    if ($makelink) {
        if ($dist === FALSE) {
            $dist = pline_surface_dist($lat1, $lng1, $lat2, $lng2);
        }
        $processed = clb_now_utc();
        $query = '';
        $query .= ', ' . RF_LINKS_DIST . '=' . $dist * 2;
        //double the distance so this is not chosen over actual tracks
        $query .= ', ' . RF_LINKS_TIME . '=' . ceil($dist / 80);
        //80 meters per minute is about 3 miles per hour
        $query .= ', ' . RF_LINKS_MODIFIED . '=' . clb_escape($processed);
        $query .= ', ' . RF_LINKS_NAME . '=' . clb_escape($name);
        $query .= ', lat=' . round(($lat1 + $lat2) / 2, PT_PRECISION);
        $query .= ', lng=' . round(($lng1 + $lng2) / 2, PT_PRECISION);
        $points = array();
        $points[] = array($lat1, $lng1, 0);
        $points[] = array($lat2, $lng2, 0);
        if ($polyline = pline_make($points, array('color' => '#00FF00'))) {
            $query .= ', ' . RF_LINKS_LINE . '=' . clb_escape(clb_join($polyline, '', '&', '='));
            $query .= ', ' . RF_LINKS_POINTS . '=' . clb_escape(clb_blob_enc($points));
        }
        if ($linkpnum) {
            $query = 'UPDATE ' . RF_LINKS_FROM . ' SET ' . trim($query, ', ') . ' WHERE ' . RF_LINKS_KEY . '=' . clb_escape($linkpnum);
        } else {
            $linkpnum = pbuild_new_pnum(RF_LINKS_FROM, RF_LINKS_KEY);
            $query .= ', ' . RF_LINKS_KEY . '=' . clb_escape($linkpnum);
            $query .= ', ' . RF_LINKS_CREATED . '=' . clb_escape($processed);
            $query .= ', ' . RF_LINKS_END1 . '=' . clb_escape($pnum1);
            $query .= ', ' . RF_LINKS_END2 . '=' . clb_escape($pnum2);
            $query .= ', ' . RF_LINKS_TYPE . '=' . clb_escape('walk');
            $query = 'INSERT INTO ' . RF_LINKS_FROM . ' SET ' . trim($query, ', ');
        }
        // qlog(__LINE__, $query);
        $wpdb->query($query);
    }
    return $makelink;
}
Esempio n. 2
0
function pfind_shortpath($node1, $node2, $links, $allowance = 4, $margin = 1.1)
{
    clb_timing(__LINE__);
    //find the destination coordinates to evaluate if paths are getting nearer or further from target
    $crowfly = FALSE;
    $dist_limit = FALSE;
    $backwards = FALSE;
    //check origin(s)
    if (!is_array($node1)) {
        $node1 = array($node1);
    }
    foreach ($node1 as $i => $pnum) {
        if (!isset($links['nodes'][$pnum]) || empty($links['nodes'][$pnum])) {
            unset($node1[$i]);
            qlog(__FUNCTION__, __LINE__, 'unknown origin in shortpath', $pnum);
        }
    }
    //check destination(s)
    if (!is_array($node2)) {
        $node2 = array($node2);
    }
    foreach ($node2 as $i => $pnum) {
        if (!isset($links['nodes'][$pnum]) || empty($links['nodes'][$pnum])) {
            unset($node2[$i]);
            qlog(__FUNCTION__, __LINE__, 'unknown destination in shortpath', $pnum);
        }
    }
    //if no origin or destination then return without searching for a route
    if (clb_count($node1) == 0 || clb_count($node2) == 0) {
        return array();
    }
    //if multiple origins but single destination, reverse direction, and reverse results at end
    if (clb_count($node1) > 1 && clb_count($node2) == 1) {
        list($node1, $node2) = array($node2, $node1);
        $backwards = TRUE;
    }
    $targets = array();
    foreach ($node2 as $i => $pnum) {
        $linkrec = FALSE;
        //this gets set as a reference parameter in parse_str
        $temp = explode(',', $links['nodes'][$pnum]);
        $linkpnum = reset($temp);
        //get first linkpnum on node
        if (isset($links['links'][$linkpnum])) {
            parse_str($links['links'][$linkpnum], $linkrec);
        }
        //get link rec by linkpnum
        //$coords = clb_val(FALSE, $linkrec, (($pnum == clb_val('', $linkrec, 'end1')) ? 'pt1' : 'pt2'));	//get end point coords for node
        $coords = isset($linkrec['end1']) && $pnum == $linkrec['end1'] ? 'pt1' : 'pt2';
        $coords = isset($linkrec[$coords]) ? $linkrec[$coords] : FALSE;
        //get end point coords for node
        if ($coords) {
            $targets[] = explode(',', $coords);
        }
        //we are just making a list of target positions so we know when we are getting close to any of them
    }
    $network_d = array();
    $queue = array();
    $dist_limit = 0;
    foreach ($node1 as $c => $pnum) {
        $linkrec = FALSE;
        //this gets set as a reference parameter in parse_str
        $temp = explode(',', $links['nodes'][$pnum]);
        $linkpnum = reset($temp);
        //get first linkpnum on node
        if (isset($links['links'][$linkpnum])) {
            parse_str($links['links'][$linkpnum], $linkrec);
        }
        //get link rec by linkpnum
        //$coords = clb_val(FALSE, $linkrec, (($pnum == clb_val('', $linkrec, 'end1')) ? 'pt1' : 'pt2'));	//get end point coords for node
        $coords = isset($linkrec['end1']) && $pnum == $linkrec['end1'] ? 'pt1' : 'pt2';
        $coords = isset($linkrec[$coords]) ? $linkrec[$coords] : FALSE;
        //get end point coords for node
        $pythag = 0;
        if ($coords) {
            //check distance from this node to each of the destinations, and use the shortest distance
            $pt = explode(',', $coords);
            //we are just making a list of target positions so we know when we are getting close to any of them
            foreach ($targets as $crowfly) {
                $temp = round(pline_surface_dist($pt[0], $pt[1], $crowfly[0], $crowfly[1]));
                if ($pythag == 0 || $temp < $pythag) {
                    $pythag = $temp;
                }
            }
        }
        $network_d[$pnum]['node'] = $pnum;
        $network_d[$pnum]['dist'] = 0;
        $network_d[$pnum]['depth'] = chr(48 + $c % 207);
        $network_d[$pnum]['prev'] = array();
        $network_d[$pnum]['ptype'] = '';
        //ptype of link not node
        $queue[$pnum] = $pythag;
        //the initial distance only really important when more than one origin.
        $dist_limit = max($pythag, $dist_limit);
    }
    $dist_limit *= $allowance;
    //expand the allowed distance by the allowance multiplier
    $complete = array();
    //collects one or more paths
    $best = FALSE;
    //will hold the lowest score of an actual match so we can stop looking after other options get to large to be contenders
    $max_depth = 0;
    //just for interest
    while (count($queue)) {
        asort($queue);
        //put lowest score first
        // qlog(__LINE__, $queue);
        $max_depth = max($max_depth, count($queue));
        $est_dist = reset($queue);
        //set first element current, and get estimated distance for this route
        $noden = key($queue);
        //get the key (node pnum)
        array_shift($queue);
        //remove item from queue since it will not need processing after this
        //$noden is the pnum of the node and is our index into the $network_d
        if (!isset($network_d[$noden])) {
            continue;
        }
        //the parent should always exist, just being safe.
        $last_dist = $network_d[$noden]['dist'];
        //distance up to the node on this leaf
        $last_depth = $network_d[$noden]['depth'];
        //number of links up to the node on this leaf
        if (is_int($best)) {
            //if we have a match and all remaining options are worse by a margin then exit this part of the process
            if ($best * $margin < $est_dist) {
                break;
            }
            /*
            	dist_limit is initially a multiple (eg 4)of the crofly distance from A to B 
            	after a path has been found this is reduced to the best path times the margin (eg 1.1)
            	so some queued items may have been under 4x limit when queued but now are longer than 1.1x best
            	so skip those items but continue looping
            */
            if ($dist_limit && $est_dist > $dist_limit) {
                continue;
            }
        }
        //if the only link to this node was by walking remember this and don't add walking links from here
        $walking_only = FALSE;
        if (isset($network_d[$noden]['prev']) && count($network_d[$noden]['prev'])) {
            $only = reset($network_d[$noden]['prev']);
            $walking_only = $only['ptype'] == 'walk';
        }
        //now loop though the candidate links from this node
        if (isset($links['nodes'][$noden]) && $links['nodes'][$noden]) {
            $links_list = explode(',', $links['nodes'][$noden]);
            foreach ($links_list as $c => $linkpnum) {
                if (array_key_exists($linkpnum, $network_d[$noden]['prev'])) {
                    continue;
                }
                //dont rescan any links already traversed towards this node
                $linkrec = FALSE;
                if (isset($links['links'][$linkpnum])) {
                    parse_str($links['links'][$linkpnum], $linkrec);
                }
                //$dist = round($last_dist + clb_val(0, $linkrec, 'dist'), 3);	//add this link distance to the total
                $dist = round($last_dist + (isset($linkrec['dist']) ? $linkrec['dist'] : 0), 3);
                //add this link distance to the total
                //$ptype = clb_val('', $linkrec, 'ptype');	//link ptype (same as nodes except for 'walk'
                $ptype = isset($linkrec['ptype']) ? $linkrec['ptype'] : '';
                //link ptype (same as nodes except for 'walk'
                if ($walking_only && $ptype == 'walk') {
                    continue;
                }
                $end1 = isset($linkrec['end1']) ? $linkrec['end1'] : '';
                //clb_val('', $linkrec, 'end1');
                $end2 = isset($linkrec['end2']) ? $linkrec['end2'] : '';
                //clb_val('', $linkrec, 'end2');
                $reverse = $noden == $end2;
                // qlog(__FUNCTION__, __LINE__, $linkpnum, $reverse, clb_val(0, $linkrec, 'reverse'));
                //when we have multiple origins, we are doing our short path backwards so we need to reverse our reverse for the real direction
                $real_direction = $backwards ? !$reverse : $reverse;
                //non reversable link and an attempt to use it in the wrong direction, skip it
                //if ($real_direction && (clb_val(0, $linkrec, 'reverse') & 1)) continue;	//reverse value of 1 means not in reverse direction
                //if (!$real_direction && (clb_val(0, $linkrec, 'reverse') & 2)) continue;	//reverse value with 2 means not in forward direction
                if ($real_direction && (isset($linkrec['reverse']) ? $linkrec['reverse'] : 0) & 1) {
                    continue;
                }
                //reverse value of 1 means not in reverse direction
                if (!$real_direction && (isset($linkrec['reverse']) ? $linkrec['reverse'] : 0) & 2) {
                    continue;
                }
                //reverse value with 2 means not in forward direction
                $otherend = $reverse ? $end1 : $end2;
                if (isset($network_d[$otherend])) {
                    //if the node has been seen before then we will not add it to the queue, but we will record how we got to it after the else.
                    //if the node reached happens to be the destination, then it is already recorded as such and no need to add it again.
                    //scan previous routes to this node
                    if (is_array($network_d[$otherend]['prev'])) {
                        foreach ($network_d[$otherend]['prev'] as $link => $prev) {
                            $round_err = max(strlen($last_depth) + 1, strlen($prev['depth']));
                            //allow a meter of rounding error for each connection
                            if (abs($prev['path_dist'] - $dist) < $round_err) {
                                //if the distance to the node within a small margin is the same, we will assume these are the same path but perhaps with different numbers of stops
                                if (strpos($last_depth, $prev['depth']) === 0) {
                                    $linkpnum = FALSE;
                                    //dont follow this link as we have been there before on this thread
                                    break;
                                } else {
                                    if (strlen($last_depth) + 1 > strlen($prev['depth'])) {
                                        unset($network_d[$otherend]['prev'][$link]);
                                    } else {
                                        $linkpnum = FALSE;
                                        //existing route had more stops so will not add this link
                                        break;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    if (in_array($otherend, $node2)) {
                        //qlog(__LINE__, clb_timing('complete '.count($complete)), $dist);
                        $complete[] = $otherend;
                        //remember the end leaf and the distance so we can easily rank results.
                        if (is_bool($best) || $dist < $best) {
                            $best = $dist;
                            $dist_limit = round($best * $margin);
                        }
                    } else {
                        //if we have coords for the end point, see how far away this link leaves us and add this to the dist
                        $pythag = 0;
                        if ($targets) {
                            //$pt = clb_val(FALSE, $linkrec, ($reverse ? 'pt1' : 'pt2'));
                            $pt = $reverse ? 'pt1' : 'pt2';
                            $pt = isset($linkrec[$pt]) ? $linkrec[$pt] : FALSE;
                            if ($pt) {
                                $pt = explode(',', $pt);
                            }
                            if ($pt) {
                                foreach ($targets as $crowfly) {
                                    $temp = round(pline_surface_dist($pt[0], $pt[1], $crowfly[0], $crowfly[1]));
                                    if ($pythag == 0 || $temp < $pythag) {
                                        $pythag = $temp;
                                    }
                                }
                            }
                        }
                        if ($dist_limit && $dist + $pythag > $dist_limit) {
                            //this is a natural thing to happen as less promising paths are abandoned, no need to log these unless debugging
                            //qlog(__FUNCTION__, __LINE__, 'branch abondoned as route longer than distance', $dist_limit, $node1, $linkpnum, $last_dist, $dist, $pythag);
                            continue;
                        }
                        // 	qlog(__LINE__, count($queue), $complete, $last_dist, $dist, $pythag, ($dist+$pythag), $dist_limit);
                        //add this leaf to the processing queue
                        $queue[$otherend] = round($dist + $pythag);
                        //this will find shortest path first
                    }
                    $network_d[$otherend]['node'] = $otherend;
                    $network_d[$otherend]['depth'] = $last_depth . chr(48 + $c % 207);
                    $network_d[$otherend]['dist'] = $dist;
                    //first one here will be shortest so keep that
                }
                if ($linkpnum) {
                    $network_d[$otherend]['prev'][$linkpnum] = array('prev_node' => $noden, 'link_pnum' => $linkpnum, 'link_len' => isset($linkrec['dist']) ? $linkrec['dist'] : 0, 'common' => $reverse ? isset($linkrec['routes2']) ? $linkrec['routes2'] : FALSE : (isset($linkrec['routes1']) ? $linkrec['routes1'] : FALSE), 'ptype' => $ptype, 'depth' => $network_d[$otherend]['depth'], 'path_dist' => $dist);
                }
            }
        }
    }
    qlog(__LINE__, 'max_depth', $max_depth, 'tree size', count($network_d));
    // qlog(__LINE__, $network_d);
    //qlog(__LINE__,$node1, $node2, $complete);
    clb_timing('shortest path');
    if (count($complete)) {
        //now run the shortest path on the new network of shortest paths but measure shortest by number of changes
        $seq = 0;
        $network_c = array();
        $queue = array();
        $queue_sort = array();
        //since change distances will be the same a lot of the time inclde a parallel distance array to pick the shortest within change groups
        foreach ($complete as $pnum) {
            $pos_c = $seq++;
            $network_c[$pos_c]['node'] = $pnum;
            //start at the destination end
            $network_c[$pos_c]['dist'] = 0;
            //distance up to the node on this leaf
            $network_c[$pos_c]['changes'] = 0;
            //number of changes to get to this leaf
            $network_c[$pos_c]['link'] = FALSE;
            //link pnum from the parent
            $network_c[$pos_c]['routes'] = array();
            //routes that the node was arrived through
            $network_c[$pos_c]['past'] = array();
            //will build up list of past nodes going forward
            $network_c[$pos_c]['ptype'] = '';
            //used to check we do not get multiple 'walk' links in a row
            $queue['x' . $pos_c] = 0;
            //the initial distance makes little difference since it is only used to choose which of the one items we use.
            $queue_sort['x' . $pos_c] = 0;
        }
        $complete = array();
        //collects one or more paths
        $best = FALSE;
        //will hold the lowest score of an actual match so we can stop looking after other options get to large to be contenders
        $range = 2;
        //allow range of best+2 extra stops
        $used = array();
        while (count($queue)) {
            //asort($queue);	//put lowest score first
            array_multisort($queue, SORT_ASC, $queue_sort, SORT_DESC);
            //$queue = changes, $queue_sort = dist
            // 	qlog(__LINE__, $queue);
            $est_changes = reset($queue);
            //set first element current, and get estimated distance for this route
            $cursor = 1 * substr(key($queue), 1);
            //get the key removing 'x' which makes the keys strings and prevents renumbering on arrays shift.
            array_shift($queue);
            //remove item from queue since it will not need processing after this
            array_shift($queue_sort);
            //remove item from queue since it will not need processing after this
            //$cursor is our index into the $network_c
            if (!isset($network_c[$cursor])) {
                continue;
            }
            //the parent should always exist, just being safe.
            $noden = $network_c[$cursor]['node'];
            //$noden is the node identifier of the leaf we want to continue the path from
            $last_dist = $network_c[$cursor]['dist'];
            //distance up to the node on this leaf
            $last_changes = $network_c[$cursor]['changes'];
            //number of changes to get to this leaf
            $last_routes = $network_c[$cursor]['routes'];
            //routes that the node was arrived through
            $last_link = $network_c[$cursor]['link'];
            //link pnum from the parent
            $past = $network_c[$pos_c]['past'];
            //will build up list of past going forward
            $past[] = $last_link;
            $last_ptype = $network_c[$cursor]['ptype'];
            //link pnum from the parent
            //if we have a match and all remaining options are worse by a margin then stop looking
            if (count($complete) && $best + $range < $est_changes) {
                break;
            }
            $used[$noden] = $pos_c;
            //our "links" are now coming from the leaves of the previous shortest path structure
            //$old_leaf = clb_val(FALSE, $network_d, $noden);	//get actual node
            $old_leaf = isset($network_d[$noden]) ? $network_d[$noden] : FALSE;
            //get actual node
            //$preds = clb_val(FALSE, $old_leaf, 'prev');		//the predecessors to that node
            $preds = isset($old_leaf['prev']) ? $old_leaf['prev'] : FALSE;
            //the predecessors to that node
            //now loop though the candidate links from this node
            if (clb_count($preds)) {
                foreach ($preds as $via_link => $pre_link) {
                    //$ptype = clb_val('', $pre_link, 'ptype');
                    $ptype = isset($pre_link['ptype']) ? $pre_link['ptype'] : '';
                    // qlog(__LINE__,$ptype, $last_ptype, $noden, (isset($pre_link['prev_node']) ? $pre_link['prev_node'] : ''));
                    if ($ptype == 'walk' && $last_ptype == 'walk') {
                        continue;
                    }
                    //don't allow a route to be constructed from a series of walk interconnections
                    if (in_array($via_link, $past)) {
                        continue;
                    }
                    //already have this link on this path so skip it
                    if ($via_link == $last_link) {
                        continue;
                    }
                    //dont double back, this test should be redundent due to the previous line
                    //$remainder = clb_val(0, $pre_link, 'path_dist');	//each pre link from the network_d array knows how far it is from the origin as a minimum
                    $remainder = isset($pre_link['path_dist']) ? $pre_link['path_dist'] : 0;
                    //each pre link from the network_d array knows how far it is from the origin as a minimum
                    //qlog(__LINE__, $last_dist, $remainder, ($last_dist + $remainder), $dist_limit, ((($last_dist + $remainder) > $dist_limit)?' culled':''));
                    if ($last_dist + $remainder > $dist_limit) {
                        continue;
                    }
                    //when expanding routes, combinations may get long so chop them out
                    //$dest_node = clb_val('', $pre_link,'prev_node');
                    $dest_node = isset($pre_link['prev_node']) ? $pre_link['prev_node'] : '';
                    //$link_len = clb_val(0, $pre_link, 'link_len');
                    $link_len = isset($pre_link['link_len']) ? $pre_link['link_len'] : 0;
                    $dist = $last_dist + $link_len;
                    //$link_routes = clb_val(FALSE, $pre_link, 'common');
                    $link_routes = isset($pre_link['common']) ? $pre_link['common'] : FALSE;
                    $link_routes = $link_routes ? explode(',', $link_routes) : array();
                    //convert comma separated list into array
                    $routes_common = array_intersect($last_routes, $link_routes);
                    $changes = count($routes_common) == 0 ? 2 : 0;
                    //if no common routes then give a change a 2 score
                    if ($changes) {
                        //see if there are any routes which have the same beginning up to '_' which indicates a branch on a line like underground lines
                        foreach ($last_routes as $rl) {
                            if (clb_contains($rl, '_')) {
                                foreach ($link_routes as $rn) {
                                    if (clb_contains($rn, '_')) {
                                        if (preg_replace('/_.*$/', '', $rl) == preg_replace('/_.*$/', '', $rn)) {
                                            $changes = 1;
                                            break;
                                        }
                                    }
                                }
                                if ($changes == 1) {
                                    break;
                                }
                            }
                        }
                        $routes_common = $link_routes;
                        //since we are changing, can now use all routes between the two nodes
                    }
                    $changes += $last_changes;
                    if (is_int($best) && $changes > $best + $range) {
                        continue;
                    }
                    $pos_c = $seq++;
                    //prepare the index for the $network_c array, we may skip the node but do not mind gaps
                    $network_c[$pos_c]['node'] = $dest_node;
                    //start at the destination end
                    $network_c[$pos_c]['prev'] = $cursor;
                    //way back to the previous leaf
                    $network_c[$pos_c]['dist'] = $dist;
                    //distance up to the node on this leaf
                    $network_c[$pos_c]['changes'] = $changes;
                    //number of changes to get to this leaf
                    $network_c[$pos_c]['link'] = $via_link;
                    //link pnum from the parent
                    $network_c[$pos_c]['routes'] = $routes_common;
                    //routes that the node was arrived through
                    $network_c[$pos_c]['past'] = $past;
                    //will build up list of past going forward
                    $network_c[$pos_c]['ptype'] = $ptype;
                    // qlog(__LINE__,$dest_node, $node1);
                    if (in_array($dest_node, $node1)) {
                        $complete[] = $pos_c;
                        if (is_bool($best) || $changes < $best) {
                            $best = $changes;
                        }
                    } else {
                        $queue['x' . $pos_c] = $changes;
                        //primary sort on changes keeps minimum changes top of list
                        $queue_sort['x' . $pos_c] = $dist;
                        //distance ranks routes with same number of changes.
                    }
                }
            }
        }
    }
    $result = array();
    if (is_array($complete)) {
        foreach ($complete as $pos_c) {
            $run = array();
            while ($link = $network_c[$pos_c]['link']) {
                $run[$link] = $network_c[$pos_c];
                //['routes'];
                $pos_c = $network_c[$pos_c]['prev'];
            }
            if ($backwards) {
                $run = array_reverse($run);
            }
            $result[] = $run;
        }
    }
    //qlog(__LINE__,count($complete), count($used), count($network_c), count($network_d));
    //qlog(__LINE__, clb_timing('shortest changes'));
    //qlog(__LINE__, $result);
    return $result;
}
Esempio n. 3
0
function pline_midpoint($points)
{
    $seg_len = 0;
    $dists = array();
    //will hold the distance for each point so we can quickly find the one before the midpoint
    $last_pt = FALSE;
    $accum = array(0, 0);
    //rather than use the last point each time, use the accumulated differences to reduce error on each link
    foreach ($points as $no => $pt) {
        $pt[0] = round($pt[0], 5);
        $pt[1] = round($pt[1], 5);
        if (!$last_pt) {
            //first loop use actual values, afterwards use differences
            $accum[0] = $pt[0];
            $accum[1] = $pt[1];
        } else {
            $dlat = $pt[0] - $accum[0];
            $dlng = $pt[1] - $accum[1];
            $accum[0] += $dlat;
            $accum[1] += $dlng;
            $dist = pline_surface_dist($pt[0], $pt[1], $last_pt[0], $last_pt[1]);
            $seg_len += $dist;
        }
        $last_pt[0] = $pt[0];
        $last_pt[1] = $pt[1];
        $dists[$no] = $seg_len;
    }
    $last_pt = FALSE;
    foreach ($dists as $no => $pos) {
        if ($last_pt && $pos > $seg_len / 2) {
            $lat = ($points[$no][0] + $last_pt[0]) / 2;
            $lng = ($points[$no][1] + $last_pt[1]) / 2;
            $elev = ($points[$no][2] + $last_pt[2]) / 2;
            return array($lat, $lng, $elev);
        }
        $last_pt = $points[$no];
    }
    return FALSE;
}