Example #1
0
function pfind_interpret($entries, $mode, &$waypoints, $path, $node_types)
{
    global $wpdb;
    $result = array();
    $result['error'] = 200;
    //start optimistically
    $result['error_str'] = 'no errors';
    $waypoints = array();
    if (clb_count($entries) <= 0) {
        $result['error'] = 400;
        $result['error_str'] = 'no locations received to parse';
        return $result;
    }
    //if only one entry we expect a a "to" separating origin and dest
    if (count($entries) == 1) {
        $entries = preg_split('/\\s+to\\s+/i', trim(reset($entries)), -1, PREG_SPLIT_NO_EMPTY);
    }
    if (clb_count($entries) == 1) {
        $result['error'] = 400;
        $result['error_str'] = 'only one location';
        return $result;
    }
    if (is_file($path)) {
        $path = dirname($path);
    }
    $path = clb_dir($path) . 'metaphones.txt';
    //like spelling city
    $index = FALSE;
    if (is_file($path)) {
        $data = file_get_contents($path);
        //, FILE_BINARY);
        $index = clb_blob_dec($data);
    }
    $pickone = array();
    foreach ($entries as $loc) {
        $loc = strtolower($loc);
        $sel = FALSE;
        $select = 'SELECT ' . RF_NODES_SELECT . ' FROM ' . RF_NODES_FROM . ' ';
        //'SELECT pnum, ptype, title, more, lat, lng FROM places ';
        $where = ' WHERE ';
        //the list of ptypes that will be used to limit the names search
        $ptypes = $node_types;
        //if more than one mode check if the user has added clarifying name to the name eg "oxford rail"
        if (count($ptypes) > 1) {
            foreach ($ptypes as $type) {
                if (clb_contains($loc, $type)) {
                    //allow the user to force a mode, by adding the code to the name
                    $ptypes = array($type);
                    //replace all other modes
                    $loc = trim(preg_replace('/\\s*\\b' . preg_quote($type) . '\\b\\s*/i', ' ', $loc));
                    //remove the signal from the name
                }
            }
        }
        //get rid of quotes and escapes
        $loc = trim(str_replace(array('\\', '"'), ' ', $loc));
        if (preg_match('/^\\s*(-?[\\.\\d]+)\\s*,\\s*(-?[\\.\\d]+)\\s*$/', $loc, $m)) {
            //waypoint given as lat/lng pair
            //limit search by node types
            if (clb_count($ptypes)) {
                $where .= ' ' . RF_NODES_TYPE . ' IN ' . clb_join($ptypes, TRUE) . ' AND ';
            }
            list($junk, $lat, $lng) = $m;
            for ($dist = 200; $dist <= 500; $dist += 100) {
                $sel = $wpdb->get_results($select . $where . within_rect($lat, $lng, $dist), ARRAY_A);
                $sel = clb_rekey($sel, RF_NODES_KEY);
                if (clb_count($sel) > 1) {
                    break;
                }
            }
            if (clb_count($sel) <= 0) {
                $result = array('error' => 602, 'error_str' => 'no tranpost node could be found near coordinates ' . $lat . ', ' . $lng);
                return $result;
            }
        } else {
            if (preg_match('/^node:\\s*(\\w+)\\s*$/', $loc, $m)) {
                //waypoint specified by pnum
                $sel = $wpdb->get_results($select . ' WHERE ' . RF_NODES_KEY . '=' . clb_escape($m[1]), ARRAY_A);
                $sel = clb_rekey($sel, RF_NODES_KEY);
            } else {
                if (in_array('rail', $ptypes) && preg_match('/^\\s*(\\w{3})\\s*$/', $loc, $m)) {
                    //rail station three letter code
                    $sel = $wpdb->get_results($select . ' WHERE ' . RF_NODES_TYPE . '="rail" AND (extref=' . clb_escape($m[1]) . ' OR ' . RF_NODES_NAME . '=' . clb_escape($m[1]) . ')', ARRAY_A);
                    $sel = clb_rekey($sel, RF_NODES_KEY);
                } else {
                    /*
                    	the primary key of the sound index structrue is the metaphone.  Inside that are ptypes using that saound.
                    	within each ptype there is a list of specific pnums using that sound in the name.
                    	on each first word, get all pnums for that sound and type, on subsequent words intesect with pnums
                    	so that we end up with pnums which have all sounds.
                    	$index[$sound][ptype][] => pnum
                    */
                    $sel = FALSE;
                    $name = pfind_unify_names($loc);
                    if (is_array($index)) {
                        $intersection = FALSE;
                        $words = preg_split('/\\W+/', $name, -1, PREG_SPLIT_NO_EMPTY);
                        foreach ($words as $w) {
                            if ($w == '&') {
                                $w = 'and';
                            }
                            $sound = metaphone($w);
                            if ($sound && isset($index[$sound])) {
                                $set = array();
                                foreach ($index[$sound] as $ptype => $nodes) {
                                    if (in_array($ptype, $ptypes)) {
                                        $set = array_merge($set, $nodes);
                                    }
                                }
                                $intersection = !is_array($intersection) ? $set : array_intersect($set, $intersection);
                            }
                        }
                        if (clb_count($intersection)) {
                            $query = $select . $where . ' ' . RF_NODES_KEY . ' IN ' . clb_join($intersection, TRUE);
                            $sel = $wpdb->get_results($query, ARRAY_A);
                            $sel = clb_rekey($sel, RF_NODES_KEY);
                        }
                    } else {
                        $query = $select . $where . ' ' . RF_NODES_NAME . ' LIKE ' . clb_escape($name . '%');
                        if (clb_count($ptypes)) {
                            $query .= ' AND ' . RF_NODES_TYPE . ' IN ' . clb_join($ptypes, TRUE);
                        }
                        $sel = $wpdb->get_results($query, ARRAY_A);
                        $sel = clb_rekey($sel, RF_NODES_KEY);
                    }
                    //if more than one match scan for common words and remove the matches if they did not contain them
                    if (clb_count($sel) > 1) {
                        foreach ($sel as $i => $row) {
                            //exact match go for it alone
                            if (strtolower($row[RF_NODES_NAME]) == strtolower($loc)) {
                                $sel = array($i => $row);
                                break;
                            }
                            //if the full name contains "road" but the requested name does not
                            //omit this choice to avoid stations like "london road" when looking for london
                            if (preg_match('/\\b(road)\\b/i', $row[RF_NODES_NAME], $m)) {
                                if (!clb_contains($loc, $m[1], FALSE)) {
                                    unset($sel[$i]);
                                }
                            }
                        }
                    }
                }
            }
        }
        if (clb_count($sel) <= 0) {
            $result = array('error' => 602, 'error_str' => 'no stations with the name ' . $loc);
            return $result;
        }
        $waypoints[] = $sel;
    }
    return $result;
}
Example #2
0
function pbuild_walk_links($ptypes, &$p2p_links, $stops_xref = FALSE, $meters = 400)
{
    global $wpdb;
    if (!is_array($ptypes)) {
        $ptypes = array($ptypes);
    }
    $toll_lat = $meters / METERS_PER_DEGREE;
    //$toll_lat is degrees equivalent of $meters in meters from the center
    $count = 0;
    //just count how many connections we are making
    $pos = array_search('plat', $ptypes);
    //dont include platforms in interchanged (we convert stations to platforms later)
    if (is_int($pos)) {
        unset($ptypes[$pos]);
    }
    $query = 'SELECT ' . RF_NODES_SELECT . ' FROM ' . RF_NODES_FROM . ' WHERE ' . RF_NODES_TYPE . ' IN ' . clb_join($ptypes, TRUE) . ' ORDER BY lat';
    $places = $wpdb->get_results($query, ARRAY_A);
    if (is_array($places)) {
        $lats = clb_column($places, 'lat');
        $lngs = clb_column($places, 'lng');
        $max = count($places);
        array_multisort($lats, SORT_ASC, $lngs, SORT_ASC, $places);
        foreach ($lats as $idx => $lat1) {
            $lng1 = $lngs[$idx];
            //allow larger degree difference in longitude because they represents fewer meters
            //also do it for each different lat
            $toll_lng = $toll_lat / cos($lat1);
            $scan = $idx + 1;
            //start one higher in the selection on each pass, as previous points already compared
            while ($scan < $max) {
                $lat2 = $lats[$scan];
                if (abs($lat2 - $lat1) > $toll_lat) {
                    break;
                }
                //all remaining latitudes will be too far away
                $lng2 = $lngs[$scan];
                if (abs($lng2 - $lng1) <= $toll_lng) {
                    //slightly extravegant, double check distance as a circle and not just a square.
                    $dist = pline_surface_dist($lat1, $lng1, $lat2, $lng2);
                    if ($dist < $meters) {
                        //nodes are within spitting distance but check if they are already connected
                        //but first check if the nodes have platforms
                        $pnum = clb_val(FALSE, $places, $idx, RF_NODES_KEY);
                        if ($stops_xref && !isset($stops_xref['stops'][$pnum])) {
                            continue;
                        }
                        //if no routes using this stop no need to include the interchange to it
                        $nodes1 = isset($p2p_links['stat2plat'][$pnum]) ? $p2p_links['stat2plat'][$pnum] : array($pnum);
                        $pnum = clb_val(FALSE, $places, $scan, RF_NODES_KEY);
                        if ($stops_xref && !isset($stops_xref['stops'][$pnum])) {
                            continue;
                        }
                        //if no routes using this stop no need to include the interchange to it
                        $nodes2 = isset($p2p_links['stat2plat'][$pnum]) ? $p2p_links['stat2plat'][$pnum] : array($pnum);
                        //normally there will only be one element in each array but if one or both has platforms we need to work the permutations
                        foreach ($nodes1 as $pnum1) {
                            foreach ($nodes2 as $pnum2) {
                                $txt = '';
                                $query = 'SELECT ' . RF_NODES_SELECT . ' FROM ' . RF_NODES_FROM . ' WHERE ' . RF_NODES_KEY . ' IN ' . clb_join(array($pnum1, $pnum2), TRUE);
                                $ends = $wpdb->get_results($query, ARRAY_A);
                                if (pbuild_make_link($p2p_links, $ends, $dist)) {
                                    $count++;
                                    $txt = '';
                                    if (is_array($ends)) {
                                        $peep = reset($ends);
                                        $txt .= $peep[RF_NODES_KEY] . ' / ' . $peep[RF_NODES_TYPE] . ' / ' . $peep[RF_NODES_NAME] . ', ';
                                        $p1 = $peep[RF_LINKS_TYPE];
                                        $peep = next($ends);
                                        $txt .= $peep[RF_NODES_KEY] . ' / ' . $peep[RF_NODES_TYPE] . ' / ' . $peep[RF_NODES_NAME] . ', ';
                                        if ($p1 == $peep[RF_LINKS_TYPE] && $p1 != 'rail') {
                                            $txt = '**** non rail ' . $txt;
                                        }
                                    }
                                    qpre(__LINE__, $count, $dist, $txt);
                                }
                            }
                        }
                        //producting of end nodes
                    }
                }
                $scan++;
            }
        }
    }
    //now ensure walking links between platforms at same station
    $query = 'SELECT ' . RF_NODES_SELECT . ' FROM ' . RF_NODES_FROM . ' WHERE ' . RF_NODES_TYPE . ' IN ' . clb_join(array('plat'), TRUE) . ' ORDER BY ' . RF_NODES_DESC;
    $places = $wpdb->get_results($query, ARRAY_A);
    if (clb_count($places)) {
        //group records by station
        $list = array();
        foreach ($places as $rec) {
            $list[$rec[RF_NODES_DESC]][] = $rec;
        }
        //get list of stations so we can access details
        $query = 'SELECT ' . RF_NODES_SELECT . ' FROM ' . RF_NODES_FROM . ' WHERE ' . RF_NODES_KEY . ' IN ' . clb_join(array_keys($list), TRUE);
        $places = $wpdb->get_results($query, ARRAY_A);
        $places = clb_rekey($places, RF_NODES_KEY);
        foreach ($list as $station => $plats) {
            if (clb_count($plats) > 1) {
                //check each platform has the name of its station in its name field
                $name = clb_val('', $places, $station, RF_NODES_NAME);
                $query = 'UPDATE ' . RF_NODES_FROM . ' SET ' . RF_NODES_NAME . '=' . clb_escape($name) . ' WHERE ' . RF_LINKS_KEY . '=';
                if ($name) {
                    foreach ($plats as $rec) {
                        if ($rec[RF_NODES_NAME] != $name) {
                            $wpdb->query($query . clb_escape($rec[RF_NODES_KEY]));
                        }
                    }
                }
                //permute platform connections
                $count = count($plats);
                for ($x = 0; $x < $count - 1; $x++) {
                    for ($y = $x + 1; $y < $count; $y++) {
                        pbuild_make_link($p2p_links, array($plats[$x], $plats[$y]));
                    }
                }
            }
        }
    }
    qlog(__LINE__, $count);
}
Example #3
0
function pline_make(&$points, $attr = FALSE)
{
    $color = clb_val('#0000FF', $attr, 'color');
    $weight = clb_val(7, $attr, 'weight');
    $opacity = clb_val(1, $attr, 'opacity');
    $pregran = clb_val(FALSE, $attr, 'pregran');
    //if points already have granularity calculated
    $max_pts = clb_val(FALSE, $attr, 'max_pts');
    //sets a target number of points for result, which is acheived by omiting detail levels
    $calc_len = clb_val(TRUE, $attr, 'calc_len');
    //option not to calculate length of segment
    $split = clb_val(FALSE, $attr, 'split');
    //split path into segments, based on segment length in meters, returns array of polylines
    $do_bounds = clb_val(FALSE, $attr, 'do_bounds');
    //include bounds in structure
    //$points: 0=>lat, 1=>lng, 2=>elev, 3=>comment from sges list on route record
    // replaced [3] with ['comment'] and ['pnum']
    $timing = FALSE;
    //timing marks for testing
    if ($timing) {
        clb_timing(__LINE__);
    }
    //initial loop here scans points to find points of greatest distance and records granularity directly in the points array
    //only points which do not lie directly between the predecessor and follower will be included in the polyline
    //the scale of the distance held allows an approprate zoom level to be assigned to each point.
    //the distance cut of point roughlyt equates to one screen pixel at full zoom, but actaul zoomlevel info added in next part not this.
    /*
    	see below for explanation and proof of formula
    	http://www.intmath.com/Plane-analytic-geometry/Perpendicular-distance-point-line.php
    	
    	distance from point (m,n) to line Ax + By + C = 0 is given by abs(Am + Bn + C) / sqrt(A^2 + B^2)
    	slope of the line is -A/B
    	to simplify the line subtract the first point from the second so that there is no incept C (ie C=0)
    	divide by A so that A becomes 1 and B becomes B/A and the distance formula becomes
    	abs(1m + (B/A)n + 0) / sqrt(1^2 + (B/A)^2)
    	abs(m + (B/A) n) / sqrt(1 + (B/A)^2)
    	in our case A is the difference of latitude and B is the differnece of longitudes
    	
    	if A is zero then we cannot divide by it but it also means the line is horizontal so the distance is just the difference in line lat and point lat
    	
    	a thrid case is when the line is only a point in which case just use pythag to get the distance
    */
    $verySmall = 1.0E-5;
    //0.00001 happens to equate to 1 screen pixel at zoom level 17
    $range = 18;
    //0= outerspce, 18=rooftops
    $numlevels = $range;
    //hard coding this so that one zoom group = one zoom level giving prceise control over point granularity
    $maxZoom = $numlevels - 1;
    $zoomFactor = pow(2, floor($range / $numlevels));
    //if every zoom level has its own zoom group then each one has a zoom factor of 2, if there are two zoom levels per group then the factor is 4.
    //set minimum distances that matter at each reverse zoom level (ie zoom level 0 has $break[$range-1])
    $breaks = array();
    for ($i = $maxZoom; $i >= 0; $i--) {
        $breaks[$i] = $verySmall * pow($zoomFactor, $i);
    }
    $points = array_values($points);
    //ensure indexes are from 0 to n-1
    $last_pt = count($points) - 1;
    if ($last_pt > 0) {
        if (!$pregran) {
            //if we have granularity on the points then we do not need to rescan
            //ensure any old granularity is removed.
            foreach ($points as $no => $pt) {
                if (isset($points[$no]['gran'])) {
                    unset($points[$no]['gran']);
                }
            }
            //using stack to scan points within line.  Start with the end points and divide into two subsets broken at
            //the point of greatest difference from the direct line between ends of the current subset
            $detail = end($breaks);
            $stack = array();
            array_push($stack, array(0, $last_pt));
            //initial values array with first and last array indicies
            $adjust = cos(deg2rad(($points[0][0] + $points[count($points) - 1][0]) / 2));
            //use one longitude adjustment factor across all latitudes based on the half way mark
            while (count($stack) > 0) {
                //stack based loop rather than recursion
                list($first, $last) = array_pop($stack);
                //since all points within subset are to be compared to the same line we can precalculate some factors of the equation
                $A = $points[$last][0] - $points[$first][0];
                $B = ($points[$last][1] - $points[$first][1]) * $adjust;
                if ($A != 0) {
                    $method = 2;
                    //assume two points in line method
                    $B = $B / $A;
                    //$A also divided by $A so becomes 1
                    $denom = sqrt(1 + pow($B, 2));
                    //since $A = 1 there is no point in using the pow function to square it and just plug in 1
                    //distance for point $x, $y now given by $dist = abs(($x - ($B * $y)) / $denom);
                } else {
                    if ($points[$last][1] == $points[$first][1]) {
                        $method = 1;
                        //if end points are coincident then simply do distance from test point to first
                    } else {
                        $method = 0;
                        //if the latitiudes of the end points are the same we would have a div by zero so will simply get difference of latitudes
                    }
                }
                $maxDist = 0;
                for ($i = $first + 1; $i < $last; $i++) {
                    $x = ($points[$i][1] - $points[$first][1]) * $adjust;
                    $y = $points[$i][0] - $points[$first][0];
                    switch ($method) {
                        case 2:
                            //two points, do point distance from line
                            $dist = abs(($x - $B * $y) / $denom);
                            break;
                        case 1:
                            //one point do pythag to get distance between points.
                            $dist = sqrt($x * $x + $y * $y);
                            break;
                        case 0:
                            //find distance by difference of lattitudes
                            //this looks wrong but si right.  The end points have the same lat so form a vertical line,
                            //the ponit we are testing therefore differs from the line by its lat also
                            $dist = abs($points[$i][0] - $points[$first][0]);
                            break;
                    }
                    //$points[$i]['dist'] = $dist;
                    if ($dist > $maxDist) {
                        $maxDist = $dist;
                        $maxLoc = $i;
                        //if($maxDist > $absMaxDist) $absMaxDist = $maxDist;	//$absMaxDist is the largest variation from the straight line, but we dont need it
                    }
                }
                //end scan of intermediate points
                if ($maxDist >= $detail) {
                    //if any point stuck out far enough
                    //the point that sticks out the most is given a distance value and will be included in the polyline
                    $gran = $maxZoom;
                    foreach ($breaks as $lvl => $limit) {
                        if ($maxDist > $limit) {
                            $gran = max(0, $lvl);
                            break;
                        }
                    }
                    $points[$maxLoc]['gran'] = $gran;
                    //also push the subsegments created when this points divides the segment just handled
                    array_push($stack, array($first, $maxLoc));
                    array_push($stack, array($maxLoc, $last));
                }
            }
        }
    }
    //set these after the granularity loop to ensure everyone keeps end points
    $points[0]['gran'] = $points[$last_pt]['gran'] = $maxZoom;
    //make sure the end points have top granularity
    $reduce = 0;
    $total = 0;
    if (is_int($max_pts)) {
        $scores = array_fill(0, count($breaks), 0);
        foreach ($points as $no => $pt) {
            if (isset($pt['gran']) && isset($scores[$pt['gran']])) {
                $scores[$pt['gran']]++;
            }
        }
        $reduce = $maxZoom;
        for ($i = $maxZoom; $i >= 0; $i--) {
            if ($total + $scores[$i] > $max_pts) {
                break;
            }
            $total += $scores[$i];
            $reduce = $i;
        }
        qlog(__LINE__, 'number of points to add', $total);
        //point count
    }
    if ($timing) {
        clb_timing('polyline gran');
    }
    $poly = array('color' => $color, 'weight' => $weight * 1, 'opacity' => $opacity * 1, 'zoomFactor' => $zoomFactor * 1, 'numLevels' => $numlevels * 1);
    $batches = array();
    //when splitting polyline collect batches in this array
    //now scan actual points again and build up polylines
    $seg_len = 0;
    $last = count($points) - 1;
    //index of last point in seg
    $pt_txt = '';
    $levels = '';
    $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
    $pt = reset($points);
    $pt[0] = round($pt[0], 5);
    //clean and consistent and ensures these are numbers not strings
    $pt[1] = round($pt[1], 5);
    $bounds = array('n' => $pt[0], 's' => $pt[0], 'e' => $pt[1], 'w' => $pt[1]);
    $count = 0;
    foreach ($points as $no => $pt) {
        if ($no === 0 || $no === $last) {
            //ensure end points get highest level of importance
            $gran = $maxZoom;
        } else {
            if (isset($pt['gran'])) {
                $gran = $pt['gran'];
                if ($gran < $reduce) {
                    continue;
                }
            } else {
                $gran = 0;
                continue;
            }
        }
        $pt[0] = round($pt[0], 5);
        //work to five decimal places as that is the precision of the polylines
        $pt[1] = round($pt[1], 5);
        //do not allow two points in a row that are identical
        if (!is_array($last_pt) || $last_pt[0] != $pt[0] || $last_pt[1] != $pt[1]) {
            $count++;
            if ($do_bounds) {
                $bounds['w'] = min($bounds['w'], $pt[1]);
                //find bounds from extreme coords
                $bounds['e'] = max($bounds['e'], $pt[1]);
                $bounds['s'] = min($bounds['s'], $pt[0]);
                $bounds['n'] = max($bounds['n'], $pt[0]);
            }
            if (!$pt_txt) {
                //first loop use actual values, afterwards use differences
                $diff = clb_b64e($pt[0]) . clb_b64e($pt[1]);
                $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;
                $diff = clb_b64e($dlat) . clb_b64e($dlng);
                if ($calc_len && $last_pt || $split) {
                    $dist = pline_surface_dist($pt[0], $pt[1], $last_pt[0], $last_pt[1]);
                    $seg_len += $dist;
                }
            }
            $level_str = clb_b64e($gran, FALSE);
        } else {
            $diff = '';
            $level_str = '';
        }
        //close off the polyline because it is the end or we are splitting it
        if (is_numeric($split) && $seg_len > $split || $no === $last) {
            $level_str = clb_b64e($maxZoom, FALSE);
            //end this seg and start next with max zoom value
            $poly['points'] = $pt_txt . $diff;
            //finish off current line with last point
            $poly['levels'] = $levels .= $level_str;
            if ($do_bounds && clb_count($bounds) == 4) {
                $poly['bounds'] = $bounds;
            }
            if ($calc_len && is_numeric($seg_len)) {
                $poly['meters'] = round($seg_len);
            }
            //this is not part of the google spec but should not cuase problems (famous last words)
            if ($split) {
                if (!isset($batches[0])) {
                    $batches[0] = $bounds;
                }
                $batches[0]['w'] = min($bounds['w'], $batches[0]['w']);
                //find bounds from extreme coords
                $batches[0]['e'] = max($bounds['e'], $batches[0]['e']);
                $batches[0]['s'] = min($bounds['s'], $batches[0]['s']);
                $batches[0]['n'] = max($bounds['n'], $batches[0]['n']);
                $batches[] = $poly;
                $seg_len = 0;
            }
            $accum[0] = $pt[0];
            $accum[1] = $pt[1];
            //start the new with the same point we just put at the end of the last sub line
            $pt_txt = clb_b64e($pt[0]) . clb_b64e($pt[1]);
            $levels = $level_str;
            $bounds = array('n' => $pt[0], 's' => $pt[0], 'e' => $pt[1], 'w' => $pt[1]);
        } else {
            $pt_txt .= $diff;
            $levels .= $level_str;
        }
        $last_pt[0] = $pt[0];
        $last_pt[1] = $pt[1];
    }
    if ($timing) {
        qlog(__FUNCTION__, __LINE__, clb_timing('encoding'), $total, $count);
    }
    //if we broke the polyline into batches then return that array not just the last $poly
    if (count($batches)) {
        return $batches;
    } else {
        return $poly;
    }
}
Example #4
0
function ajax_request()
{
    global $editor_types, $editor_tables;
    $xml = '';
    $msg = '';
    $rec_count = 0;
    $db = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
    $pnum = clb_val(FALSE, $_REQUEST, 'pnum');
    if ($new_mark = preg_match('/^b(\\w{7})(\\w{7})/', $pnum, $m)) {
        $_REQUEST['lat'] = hexdec($m[1]) / 100000 - 180;
        $_REQUEST['lng'] = hexdec($m[2]) / 100000 - 180;
        $_REQUEST['coords'] = clb_b64e($_REQUEST['lat']) . clb_b64e($_REQUEST['lng']);
    }
    $ptype = clb_val(FALSE, $_REQUEST, 'ptype');
    //if the ptype is cust, default to the first table and type in the definitions that does or does not have a polyline
    if ($ptype == 'cust' && $new_mark) {
        foreach ($editor_types as $ptype => $spec) {
            if (clb_val(FALSE, $spec, 'polyline') == isset($_REQUEST['polyline'])) {
                break;
            }
        }
    }
    $table = FALSE;
    $prefixes = clb_column($editor_tables, 'prefix');
    if ($pnum && preg_match('/^(\\w+)_\\w+$/', $pnum, $m)) {
        $table = array_search($m[1], $prefixes);
    } else {
        if ($ptype) {
            $table = clb_val(FALSE, $editor_types, $ptype, 'table');
        }
    }
    $spec = clb_val(FALSE, $editor_tables, $table);
    $ajax = clb_val(FALSE, $_REQUEST, 'ajax');
    qlog(__LINE__, '>>>>', $ajax, $pnum, $ptype, $table, $new_mark ? 'new' : 'old');
    //, $spec);
    switch ($ajax) {
        case 'show':
            $sel = FALSE;
            if ($spec) {
                $select = clb_val(FALSE, $spec, 'select');
                $query = 'SELECT ' . clb_join($select, '`') . ' FROM ' . $table . ' WHERE pnum=' . clb_escape($pnum);
                $sel = $db->get_results($query, ARRAY_A);
            }
            //if not found via pnum, try title in each table.
            if (!$sel) {
                foreach ($editor_tables as $table => $spec) {
                    if (($select = clb_val(FALSE, $spec, 'select')) && in_array('title', $select)) {
                        $query = 'SELECT ' . clb_join($select, '`') . ' FROM ' . $table . ' WHERE title like ' . clb_escape($pnum . '%');
                        $sel = $db->get_results($query, ARRAY_A);
                        if ($sel) {
                            break;
                        }
                    }
                }
            }
            if (!$sel) {
                $msg = 'No matches found for: ' . $pnum;
            } else {
                $titles = clb_column($sel, 'title');
                $msg = count($sel) . ' matches found: ' . join(', ', $titles);
                $rec = reset($sel);
                $pnum = clb_val(FALSE, $rec, 'pnum');
                $xml .= clb_tag('response', '', '', array_merge(array('type' => 'centre'), array_intersect_key($rec, array('lat' => 0, 'lng' => 0)))) . "\n";
                $xml .= refesh_marker($db, $table, $pnum);
                $xml .= marker_bubble($db, $spec, $table, $pnum);
            }
            break;
        case 'route_list':
            //shows bubble on station showing list of routes
            $html = '';
            //find the route table and which field(s) hold the stop list
            $route_flds = '';
            foreach ($editor_tables as $route_tab => $info) {
                if ($route_flds = clb_val(FALSE, $info, 'routes')) {
                    break;
                }
            }
            if (!$route_flds) {
                break;
            }
            $route_flds = explode('/', $route_flds);
            //can be more than one field with '/' as a separator
            //build query to get route list
            $select = clb_val(FALSE, $editor_tables, $route_tab, 'select');
            $where = array();
            foreach ($route_flds as $fld) {
                $where[] = ' (`' . $fld . '` LIKE ' . clb_escape('%' . $pnum . '%') . ')';
            }
            $query = 'SELECT ' . clb_join(array_merge($select, $route_flds), '`') . ' FROM ' . $route_tab . ' WHERE ' . join(' OR ', $where);
            $sel = $db->get_results($query, ARRAY_A);
            if (clb_count($sel) == 0) {
                $msg = 'There are no routes for node: ' . $pnum;
            } else {
                $list = '';
                $alt = 0;
                foreach ($sel as $rec) {
                    foreach ($route_flds as $pos => $fld) {
                        $rnum = reset($rec);
                        $route_key = key($rec);
                        $script = 'map_ajax(the_map, \'show_route\', {\'pnum\':\'' . $rnum . '\',\'fld\':\'' . $fld . '\', \'stop\':\'' . $pnum . '\'});';
                        $name = $rnum . ':' . $pos . ': ' . clb_val(FALSE, $rec, 'title');
                        $list .= clb_tag('li', '', clb_tag('a', $name, '', array('onclick' => $script, 'href' => 'javascript:void(0);')), array('class' => 'alt' . $alt++ % 2));
                    }
                }
                $html .= clb_tag('ul', '', $list, array('class' => 'route_list')) . "\n";
                $form = clb_tag('form', '', $html, array('id' => 'info_win', 'action' => '', 'method' => 'get', 'onsubmit' => 'return false;')) . "\n";
                $xml .= clb_tag('response', '', htmlspecialchars($form), array('type' => 'bubble', 'pnum' => $pnum)) . "\n";
            }
            break;
        case 'new_route':
            //create new route
        //create new route
        case 'route_stop':
            //add stop to route
        //add stop to route
        case 'route_unstop':
            //remove stop from route
        //remove stop from route
        case 'show_route':
            //show route
            //		qlog(__LINE__, $table, $pnum, $spec);
            require_once CODE_DIR . 'pline_lib.php';
            //scan tables to find routes
            foreach ($editor_tables as $table => $info) {
                if ($routes = clb_val(FALSE, $info, 'routes')) {
                    break;
                }
            }
            if (!$routes) {
                break;
            }
            //did not find route table
            $routes = explode('/', $routes);
            $route_tab = $table;
            $select = clb_val(FALSE, $editor_tables, $route_tab, 'select');
            $route_key = reset($select);
            $stops = FALSE;
            $new_route = 'new_route' == $ajax;
            if ($new_route) {
                $fld = reset($routes);
                $newstop = $pnum;
                $stopindex = 0;
                $list = '';
                $title = clb_val(FALSE, $_REQUEST, 'title');
                $pnum = new_pnum($db, $table, $route_key);
                $ajax = 'route_stop';
            } else {
                $stopindex = clb_val(FALSE, $_REQUEST, 'stopindex');
                //this only come with route_stop and route_unstop
                $newstop = clb_val(FALSE, $_REQUEST, 'newstop');
                //this only come with route_stop
                $fld = clb_val(FALSE, $_REQUEST, 'fld');
                $select = array_merge($select, $routes);
                //select route record
                $query = 'SELECT ' . clb_join($select, '`') . ' FROM ' . $route_tab . ' WHERE ' . $route_key . '=' . clb_escape($pnum);
                $sel = $db->get_results($query, ARRAY_A);
                $rec = clb_count($sel) ? reset($sel) : FALSE;
                $list = clb_val(FALSE, $rec, $fld);
                $ptype = clb_val(FALSE, $rec, 'ptype');
                $title = clb_val(FALSE, $rec, 'title');
                //if (empty($list) && (reset($routes) == $fld) && ($fld
                if (empty($list)) {
                    $newstop = clb_val(FALSE, $_REQUEST, 'stop');
                    $stopindex = 0;
                    $ajax = 'route_stop';
                }
            }
            if (preg_match_all('/^(\\w+)\\s+(.*)/m', $list, $m)) {
                $stops = $m[1];
            }
            if (in_array($ajax, array('route_stop', 'route_unstop')) && is_numeric($stopindex)) {
                if (!$stops) {
                    $stops = array(FALSE);
                }
                //ensure loop runs at least once
                $new = '';
                foreach ($stops as $i => $stop_pnum) {
                    if ('route_unstop' == $ajax && $i == $stopindex) {
                        continue;
                    }
                    //skip the stop that is to be deleted
                    //add the stop on this line
                    if ($stop_pnum) {
                        $new .= $m[1][$i] . ' ' . trim($m[2][$i]) . "\n";
                    }
                    //add new station if this is the right position
                    if ('route_stop' == $ajax && $i == $stopindex && $newstop) {
                        //find maker table via ptype
                        $table = clb_val(FALSE, $editor_types, $ptype, 'table');
                        $query = 'SELECT lat, lng, pnum, ptype, title FROM ' . $table . ' WHERE pnum=' . clb_escape($newstop);
                        $sel = $db->get_results($query, ARRAY_A);
                        if ($sel) {
                            $new .= $newstop . ' ' . clb_val('', reset($sel), 'title') . "\n";
                        }
                    }
                }
                if (preg_match_all('/^(\\w+)\\s+(.*)/m', $new, $m)) {
                    $stops = $m[1];
                }
                //if forward direction and changing last item update orig, dest and title
                $rename = '';
                if (reset($routes) == $fld && clb_count($stops) <= $stopindex + 2) {
                    $orig = reset($m[2]);
                    $dest = end($m[2]);
                    $rename .= ', title=' . clb_escape($orig . ' - ' . $dest);
                    $rename .= ', orig=' . clb_escape($orig);
                    $rename .= ', dest=' . clb_escape($dest);
                }
                if ($new_route) {
                    $query = 'SELECT area, count(*) AS c FROM ' . $route_tab . ' WHERE ptype=' . clb_escape($ptype) . ' GROUP BY area';
                    $sel = $db->get_results($query, ARRAY_A);
                    $area = is_array($sel) ? clb_val('', reset($sel), 'area') : '';
                    $query = '';
                    $query .= ', ' . $route_key . '=' . clb_escape($pnum);
                    $query .= ', area=' . clb_escape($area);
                    $query .= ', ptype=' . clb_escape($ptype);
                    $query .= ', ' . $fld . '=' . clb_escape($new);
                    $query .= ', created=' . clb_escape(clb_now_utc());
                    $query = 'INSERT INTO ' . $route_tab . ' SET ' . trim($query, ', ') . $rename;
                } else {
                    $query = 'UPDATE ' . $route_tab . ' SET ' . $fld . '=' . clb_escape($new) . $rename . ' WHERE ' . $route_key . '=' . clb_escape($pnum);
                }
                $db->query($query);
            }
            if ($stops) {
                $index = array_search(clb_val(FALSE, $_REQUEST, 'stop'), $stops);
                //index of the stop we opened route from
                if (is_numeric($stopindex)) {
                    $index = Min($stopindex + ($newstop ? 1 : 0), clb_count($stops) - 1);
                }
                //use new index if provided and add one if new stop
                if (preg_match('/^(\\w+)_\\w+$/', reset($stops), $m)) {
                    $table = array_search($m[1], $prefixes);
                    $spec = clb_val(FALSE, $editor_tables, $table);
                    $points = array();
                    $names = array();
                    $pnums = array();
                    $query = 'SELECT lat, lng, pnum, ptype, title FROM ' . $table . ' WHERE pnum IN ' . clb_join($stops, TRUE);
                    $sel = $db->get_results($query, ARRAY_A);
                    //in theory could be multiple stop instances and need to give points in order so loop on $stops and look up record via xref
                    $xref = clb_column($sel, 'pnum');
                    if (clb_count($sel)) {
                        foreach ($stops as $stop_pnum) {
                            $rec = clb_val(FALSE, $sel, array_search($stop_pnum, $xref));
                            $points[] = array($rec['lat'], $rec['lng'], 0);
                            $names[] = str_replace('|', ',', $rec['title']);
                            $pnums[] = $rec['pnum'];
                            $rec['type'] = 'marker';
                            $xml .= clb_tag('response', '', '', $rec) . "\n";
                            $rec_count++;
                        }
                    }
                    foreach ($points as $i => $pt) {
                        if (!is_array($pt)) {
                            unset($points[$i]);
                        }
                    }
                    //remove non points if there are any
                    $line = pline_make($points, array('color' => '#FF0000'));
                    $line['names'] = join('|', $names);
                    $line['pnums'] = join('|', $pnums);
                    if ($line) {
                        $line = clb_join($line, '', '&', '=');
                    }
                    $attr = array('type' => 'route_pline', 'pnum' => $pnum, 'title' => $title, 'fld' => $fld, 'ptype' => $ptype, 'index' => $index);
                    if ($line) {
                        $xml .= clb_tag('response', '', htmlspecialchars($line), $attr) . "\n";
                    }
                }
            } else {
                $msg = 'This route (in this direction) has no stops. ';
            }
            break;
        case 'overlays':
            if (clb_val(FALSE, $_REQUEST, 'zm') < 9) {
                $msg = 'Zoom in to get markers to download.';
            } else {
                $rect = array();
                $rect[] = 'lat >= ' . clb_val(FALSE, $_REQUEST, 'bot');
                $rect[] = 'lng >= ' . clb_val(FALSE, $_REQUEST, 'lft');
                $rect[] = 'lat <= ' . clb_val(FALSE, $_REQUEST, 'top');
                $rect[] = 'lng <= ' . clb_val(FALSE, $_REQUEST, 'rgt');
                $qtypes = preg_split('/;/', clb_val(FALSE, $_REQUEST, 'types'), -1, PREG_SPLIT_NO_EMPTY);
                $tables = array();
                foreach ($qtypes as $ptype) {
                    $tables[clb_val('bad', $editor_types, $ptype, 'table')][] = $ptype;
                }
                if (!count($qtypes)) {
                    $msg = 'No marker types selected.';
                } else {
                    foreach ($tables as $table => $list) {
                        if ($table != 'bad' && count($list)) {
                            $prefix = clb_val(FALSE, $editor_tables, $table, 'prefix');
                            $types = preg_replace('/\\w+_/', '', clb_join($list, TRUE));
                            $query = '';
                            $query .= 'SELECT lat, lng, pnum, ptype, title FROM ' . $table . ' WHERE ';
                            $query .= ' ptype IN ' . $types . ' AND (' . join(' AND ', $rect) . ') ';
                            $sel = $db->get_results($query, ARRAY_A);
                            if (clb_count($sel)) {
                                foreach ($sel as $rec) {
                                    $rec['type'] = 'marker';
                                    if (!in_array($rec['ptype'], $list)) {
                                        $rec['ptype'] = $prefix . '_' . $rec['ptype'];
                                    }
                                    $xml .= clb_tag('response', '', '', $rec) . "\n";
                                    $rec_count++;
                                }
                            }
                        }
                    }
                }
                $msg = $rec_count ? count($sel) . ' markers loaded' : 'No markers found.';
                if ('purge' == clb_val(FALSE, $_REQUEST, 'purge')) {
                    $xml .= clb_tag('response', '', '', array('type' => 'purge')) . "\n";
                }
            }
            break;
        case 'saveline':
            require_once CODE_DIR . 'pline_lib.php';
            //fall through
        //fall through
        case 'save':
            //no real validation so just save and close
            if (!$spec) {
                $msg = 'could not identify the marker type.';
                break;
            }
            //('polyline'=>'line', 'select'=>' lat, lng, pnum, ptype, title, line, aoe_data')
            if ($new_mark) {
                $pnum = new_pnum($db, $table);
            }
            //get field names and types
            $def = array();
            $sel = $db->get_results('describe ' . $table, ARRAY_A);
            foreach ($sel as $rec) {
                $def[$rec['Field']] = $rec['Type'];
            }
            /*
            	normally save line is handled by the normal save 
            	but if we are saving a cut line, we need to save off the first part and 
            	then use the normal save to create the latter part as a new record
            	dont cut on first or last point of line
            */
            $points = FALSE;
            if ('saveline' == $ajax) {
                $points = pline_pts_arr(clb_val(FALSE, $_REQUEST, 'polyline'));
                //the rest of this is only for cutting a line
                if (($cut = clb_val(FALSE, $_REQUEST, 'cut')) && $cut + 1 < clb_count($points)) {
                    $first = array_slice($points, 0, $cut + 1);
                    //keep points up to and including cut
                    $points = array_slice($points, $cut);
                    //reduce points on and after cut for new record
                    $query = save_line_query($first, $spec);
                    $query .= '`' . 'lat' . '`=' . clb_escape($_REQUEST['lat']) . ',';
                    $query .= '`' . 'lng' . '`=' . clb_escape($_REQUEST['lng']) . ',';
                    $query .= '`' . 'end1' . '`=' . clb_escape($_REQUEST['end1']) . ',';
                    //adjusts mid point
                    $query .= '`' . 'end2' . '`=' . clb_escape($_REQUEST['end2']) . ',';
                    if ($new_mark) {
                        $query .= '`' . 'pnum' . '`=' . clb_escape($pnum) . ',';
                        $query .= '`' . 'ptype' . '`=' . clb_escape($ptype) . ',';
                        if (isset($def['created'])) {
                            $query .= '`' . 'created' . '`=' . clb_escape(clb_now_utc()) . ',';
                        }
                        $query = 'INSERT INTO ' . $table . ' SET ' . trim($query, ', ');
                    } else {
                        $query = 'UPDATE ' . $table . ' SET ' . trim($query, ', ') . ' WHERE pnum=' . clb_escape($pnum);
                    }
                    $res = $db->query($query);
                    $xml .= refesh_marker($db, $table, $pnum, $pnum);
                    unset($_REQUEST['pnum']);
                    //clear this so that the new marker does not remove the repositioned marker
                    $pnum = new_pnum($db, $table);
                    //new pnum for marker
                    $new_mark = TRUE;
                }
            }
            $query = '';
            if ('saveline' == $ajax && is_array($points)) {
                $query .= save_line_query($points, $spec);
            }
            foreach ($def as $fld => $type) {
                switch ($fld) {
                    case 'pnum':
                        if ($new_mark) {
                            $query .= '`' . $fld . '`=' . clb_escape($pnum) . ',';
                        }
                        break;
                    case 'created':
                        if ($new_mark) {
                            $query .= '`' . $fld . '`=' . clb_escape(clb_now_utc()) . ',';
                        }
                        break;
                    case 'ptype':
                        $query .= '`' . $fld . '`=' . clb_escape($ptype) . ',';
                        break;
                    default:
                        if (isset($_REQUEST[$fld])) {
                            $query .= '`' . $fld . '`=' . clb_escape($_REQUEST[$fld]) . ',';
                        }
                        break;
                }
            }
            qlog(__LINE__, $query);
            if ($new_mark) {
                $query = 'INSERT INTO ' . $table . ' SET ' . trim($query, ', ');
            }
            if (!$new_mark) {
                $query = 'UPDATE ' . $table . ' SET ' . trim($query, ', ') . ' WHERE pnum=' . clb_escape($pnum);
            }
            $res = $db->query($query);
            //when saving a marker remember the type to be used as the default for next new marker.
            $name = clb_val(FALSE, $spec, 'polyline') ? 'type_line' : 'type_mark';
            $xml .= clb_tag('response', '', $ptype, array('type' => 'state', 'pnum' => $name)) . "\n";
            //pnum is the "id" name is the "id" of the state we are setting
            $xml .= refesh_marker($db, $table, $pnum, clb_val(FALSE, $_REQUEST, 'pnum'));
            //want to fall through to show a bubble if saving a line
            //so break when either condition fails
            if ('saveline' == $ajax) {
                $xml .= marker_bubble($db, $spec, $table, $pnum);
            }
            break;
        case 'bubble':
            if (!$spec || !$pnum) {
                $msg = 'could not identify the marker type.';
                break;
            }
            $xml .= marker_bubble($db, $spec, $table, $pnum);
            break;
        case 'delete':
            $query = 'DELETE FROM ' . $table . ' WHERE pnum=' . clb_escape($pnum);
            $sel = $db->query($query);
            //remove old marker, which closes info box
            $xml .= clb_tag('response', '', '', array('type' => 'remove', 'pnum' => $_REQUEST['pnum'])) . "\n";
            break;
    }
    if ($ajax) {
        if ($msg) {
            $xml .= clb_tag('response', $msg, '', array('type' => 'info')) . "\n";
        }
        if (!$xml) {
            $xml .= clb_tag('response', '', '', array('type' => 'null')) . "\n";
        }
        // qlog(__LINE__, $xml);
        clb_response('xml', $xml);
    }
}
Example #5
0
function blow_backout($node1, $node2, $network_d, $links)
{
    //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
    $dist_limit = FALSE;
    foreach ($node2 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;
        if (isset($network_d[$pnum]) && ($dist_limit === FALSE || $dist_limit > $network_d[$pnum]['dist'])) {
            $dist_limit = $network_d[$pnum]['dist'];
        }
    }
    $dist_limit *= 1.1;
    //don't allow paths to get more than 20% longer than the best.
    $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();
    $time = microtime(true);
    while (count($queue)) {
        //asort($queue);	//put lowest score first
        array_multisort($queue, SORT_ASC, $queue_sort, SORT_DESC);
        //$queue = changes, $queue_sort = dist
        if ((microtime(true) - $time) * 1000 > 5000) {
            $time = microtime(true);
            qlog(__LINE__, 'queue', count($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.
                }
            }
        }
    }
    //if (count($complete) == 0) {qpre($node1, $node2, $network_d, $network_c, $preds);	exit();}
    $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'];
            }
            $result[] = $run;
        }
    }
    //qlog(__LINE__,count($complete), count($used), count($network_c), count($network_d));
    //qlog(__LINE__, clb_timing('shortest changes'));
    //qlog(__LINE__, $node2, $complete);
    return $result;
}
Example #6
0
            }
        }
        inspect_data($path, 1);
    }
    echo clb_tag('pre', '', clb_tag('code', $cmd . 'p2p'));
    echo clb_tag('h3', 'Interchanges Process');
    echo clb_tag('p', 'This process looks at stations/stops accessed by routes (as given in the stops file) and determines which nodes are
	close but not connected.  It then creates walk links if the nodes are within 400m of each other.  This process relies on the p2p file 
	so walk links cannot be generated before the p2p, but the p2p file needs to be regenerated after running this process.');
    if (!is_file($p2p_path)) {
        echo clb_tag('p', 'There is no p2p file, you cannot run this process until it exists', '', array('style' => 'color:red;'));
    } else {
        $time = $test = clb_escape(clb_now_utc(filemtime($p2p_path)));
        if (is_file($stops_path)) {
            $test = clb_escape(clb_now_utc(filemtime($stops_path)));
        }
        //check station to station links of given types
        $query = 'SELECT 1 FROM ' . RF_LINKS_FROM . ' WHERE ' . RF_LINKS_MODIFIED . ' > ' . $time . ' AND ' . RF_LINKS_TYPE . ' IN ' . clb_join($node_types, TRUE);
        $links = $wpdb->get_results($query, ARRAY_A);
        if ($time < $test) {
            echo clb_tag('p', 'The stops file is more recent than this file and this file should be regenerated.', '', array('style' => 'color:red;'));
        } else {
            if (clb_count($links) > 0) {
                echo clb_tag('p', clb_count($links) . ' station to statio links have been added or updates so this should be rebuilt.', '', array('style' => 'color:#f1a629;'));
            } else {
                echo clb_tag('p', 'This file seems up to date', '', array('style' => 'color:green;'));
            }
        }
    }
    echo clb_tag('pre', '', clb_tag('code', $cmd . 'walk'));
}