function import_new_geometry() { global $conn, $comment, $is_map, $is_new_document, $culture, $name, $map_editor, $map_scale, $map_code, $keepassociations, $region_type, $newgeomtext, $no_oldgeom, $document_id, $a_type, $fullwipe, $oldgeom, $newgeom, $prgmsg; info("Importing the new geometry...\n"); try { $conn->beginTransaction(); $history_metadata = new HistoryMetadata(); $history_metadata->setComment(isset($comment) ? $comment : ($is_new_document ? 'Imported new ' . ($is_map ? 'map' : 'area') : 'Updated geometry')); $history_metadata->set('is_minor', false); $history_metadata->set('user_id', 2); // C2C user $history_metadata->save(); if ($is_new_document) { $doc = $is_map ? new Map() : new Area(); $doc->setCulture($culture); $doc->set('name', $name); if ($is_map) { $doc->set('editor', $map_editor); $doc->set('scale', $map_scale); $doc->set('code', $map_code); } else { $doc->set('area_type', $region_type); } } else { $doc = Document::find($is_map ? 'Map' : 'Area', $document_id); $name = $doc->get('name'); if (!$is_map) { $region_type = $doc->get('area_type'); } } $doc->set('geom_wkt', $newgeomtext); $doc->save(); info("Geometry uploaded.\n"); if ($keepassociations) { exit; } if ($is_new_document) { $document_id = $doc->get('id'); } // $conn->commit(); // $conn->beginTransaction(); if ($is_map) { $a_type = 'dm'; } else { switch ($region_type) { case 1: // range $a_type = 'dr'; break; case 2: // country $a_type = 'dc'; break; case 3: // dept $a_type = 'dd'; break; } } // Some explanation for the following queries: // - && operator is used to limit docs to the one whose bouding boxes overlap (it uses spatial index) // - ST_Within and ST_Intersects are used to work on the actual geometries // - ST_Within apears to be faster, so we use it for 'points' (like summits, huts etc), but we have // to use ST_Intersects for 'geometries' (like outings, maps etc) // - we only use a buffer of 200m for areas (because of boundaries imprecision), but not for maps // - areas are not linked together // - maps are not linked to outings, users, and other maps // if it is a new document, we create geoassociations for the whole geometry // but if its an updated one, we only create geoassociations for the part of the // new geometry that does not intersect with the old one if ($is_new_document || $no_oldgeom || $fullwipe) { // retrieve geom from the database $geomquery = '(SELECT geom FROM ' . ($is_map ? 'maps' : 'areas') . ' WHERE id=?)'; $geomqueryb = '(SELECT buffer(geom, 200) FROM ' . ($is_map ? 'maps' : 'areas') . ' WHERE id=?)'; $queryparam = array($document_id, $document_id); } else { $queryparam = array(); $creategeom = $conn->standaloneQuery("SELECT ST_Difference('{$newgeom}', '{$oldgeom}')")->fetchAll(); $creategeomb = $conn->standaloneQuery("SELECT ST_Difference(buffer('{$newgeom}', 200), buffer('{$oldgeom}', 200))")->fetchAll(); $creategeom = $creategeom[0]['st_difference']; $creategeomb = $creategeomb[0]['st_difference']; $geomquery = "'{$creategeom}'"; $geomqueryb = "'{$creategeomb}'"; } // for maps, we don't use buffer at all if ($is_map) { $geomqueryb = $geomquery; } $queries = array(); // point geometry $queries[] = array("SELECT id, module FROM documents WHERE geom && {$geomqueryb} " . "AND ST_Within(geom, {$geomqueryb}) " . "AND module IN('summits', 'huts', 'sites', 'parkings', 'products', 'portals', 'images'" . ($is_map ? '' : ", 'users'") . ')', $queryparam); // multipoint geometry $queries[] = array("SELECT id, module FROM documents WHERE geom && {$geomqueryb} " . "AND ST_Intersects(geom, {$geomqueryb}) AND module" . ($is_map ? "='routes'" : " IN('routes', 'outings')"), $queryparam); // for maps areas associations, we always compute 'full wipe', without buffer $geomquery = '(SELECT geom FROM ' . ($is_map ? 'maps' : 'areas') . ' WHERE id=?)'; $queries[] = array("SELECT id, module FROM documents WHERE geom && {$geomquery} " . "AND ST_Intersects(geom, {$geomquery}) AND module='" . ($is_map ? 'areas' : 'maps') . "'", array($document_id, $document_id)); $results_a = array(); foreach ($queries as $query) { $results_a[] = $conn->standaloneQuery($query[0], $query[1])->fetchAll(); } $results = array(); foreach ($results_a as $results_set) { foreach ($results_set as $d) { $results[] = $d; } } $prgmsg = "Create new associations..."; info($prgmsg); $tot = count($results); foreach ($results as $i => $d) { progression($i, $tot); // Apparently in some cases, we ar trying to create associations that // already exist, so we check first if (!GeoAssociation::find($document_id, $d['id'], null, false)) { $a = new GeoAssociation(); $created[$d['module']] = isset($created[$d['module']]) ? $created[$d['module']] + 1 : 1; // for map - area geoassociations, links must not be dm but dr, dc, dd... if ($is_map && $d['module'] === 'areas') { $area = Document::find('Area', $d['id']); switch ($area->get('area_type')) { case 1: // range $t_a_type = 'dr'; break; case 2: // country $t_a_type = 'dc'; break; case 3: // dept $t_a_type = 'dd'; break; } $a->doSaveWithValues($document_id, $d['id'], $t_a_type); } else { $a->doSaveWithValues($d['id'], $document_id, $a_type); } } // inherited docs: we add geoassociations for the 'inherited docs' from sites, routes and summits // but not if they already have a geometry (gps track) switch ($d['module']) { case 'sites': case 'routes': if ($is_map) { break; } // we do not link maps to outings $associated_outings = Association::findAllAssociatedDocs($d['id'], array('id', 'geom_wkt'), $d['module'] === 'routes' ? 'ro' : 'to'); if (count($associated_outings)) { foreach ($associated_outings as $outing) { if (!$outing['geom_wkt'] && GeoAssociation::find($outing['id'], $document_id, $a_type) === false) { // we create geoassociation (if it already existed, it has been deleted before in the script) $a = new GeoAssociation(); $a->doSaveWithValues($outing['id'], $document_id, $a_type); $created['outings'] = isset($created['outings']) ? $created['outings'] + 1 : 1; } } } break; case 'summits': // if summit is of type raid, we should not try to update its routes and outings summit_type=5 $summit = Document::find('Summit', $d['id']); if ($summit->get('summit_type') == 5) { break; } $associated_routes = Association::findAllAssociatedDocs($d['id'], array('id', 'geom_wkt'), 'sr'); if (count($associated_routes)) { foreach ($associated_routes as $route) { $i = $route['id']; if (!$route['geom_wkt'] && GeoAssociation::find($i, $document_id, $a_type) === false) { $a = new GeoAssociation(); $a->doSaveWithValues($i, $document_id, $a_type); $created['routes'] = isset($created['routes']) ? $created['routes'] + 1 : 1; if (!$is_map) { $associated_outings = Association::findAllAssociatedDocs($i, array('id', 'geom_wkt'), 'ro'); if (count($associated_outings)) { foreach ($associated_outings as $outing) { $j = $outing['id']; if (!$outing['geom_wkt'] && GeoAssociation::find($j, $document_id, $a_type) === false) { $a = new GeoAssociation(); $a->doSaveWithValues($j, $document_id, $a_type); $created['outings'] = isset($created['outings']) ? $created['outings'] + 1 : 1; } } } } } } } break; } } info("\n"); $conn->commit(); if (isset($created)) { associations_result($created); } if ($is_new_document) { info('Added new ' . ($is_map ? 'map' : 'area') . " {$name} ({$document_id})\n"); } else { info('Updated ' . ($is_map ? 'map' : 'area') . " ({$document_id})\n"); } } catch (Exception $e) { $conn->rollback(); throw $e; } }