Як легко перенести всі функції у векторний набір даних?


33

Скажімо, я склав Shapefile, і всі функції мають їх вершини зміщені на постійну кількість. Який найпростіший спосіб змістити всі ознаки (звідси (x, y) положення їх вершин) довільним зсувом? У мене є безліч файлів, до яких я б застосував це виправлення, тому відповідь на Bash / OGR буде кращим :)

Нарешті, я для цього використав Spatialite, оскільки він має приємну функцію ShiftCoords. Однак нитка була дуже інформативною! Дякую всім!


Я просто люблю цей запис. Вся ця сторінка - чудовий приклад запитань і запитань. Безпосередньо чітко описане питання, і кожна відповідь дає унікальне, достовірне та повне рішення. Це красиво. Я виступав за кожного, кожен за своїми заслугами.
matt wilkie

@Jose Цей пост потребує невеликого оновлення через відносно недавніх удосконалень бібліотеки GDAL. Зараз є одне рішення вкладиша (див. Відповідь нижче)! Можна використовувати функцію SpatiaLite ShiftCoords безпосередньо за допомогою утиліти ogr2ogr.
Антоніо Фальчіано

Відповіді:


21

Використання JEQL Це можна зробити за допомогою трьох рядків:

ShapefileReader t file: "shapefile.shp";
out = select * except (GEOMETRY), Geom.translate(GEOMETRY,100,100) from t;
ShapefileWriter out file: "ahapefile_shift.shp";

передній край! приємно!
WolfOdrade

Приємно, Девіде. Це тісно.
sgillies

1
Просто треба вказати ... "ahapefile?"
WolfOdrade

Я в кінцевому підсумку використовував функцію перекладу Spatialite, яка схожа на ту, яку ви запропонували тут.
Хосе

30

Я створив Fiona (OGR обгортку), щоб зробити цю обробку простою.

from fiona import collection
import logging

log = logging.getLogger()

# A few functions to shift coords. They call eachother semi-recursively.
def shiftCoords_Point(coords, delta):
    # delta is a (delta_x, delta_y [, delta_y]) tuple
    return tuple(c + d for c, d in zip(coords, delta))

def shiftCoords_LineString(coords, delta):
    return list(shiftCoords_Point(pt_coords, delta) for pt_coords in coords)

def shiftCoords_Polygon(coords, delta):
    return list(
        shiftCoords_LineString(ring_coords, delta) for ring_coords in coords)

# We'll use a map of these functions in the processing code below.
shifters = {
    'Point': shiftCoords_Point,
    'LineString': shiftCoords_LineString,
    'Polygon': shiftCoords_Polygon }

# Example 2D shift, 1 unit eastward and northward
delta = (1.0, 1.0)

with collection("original.shp", "r") as source:

    # Create a sink for processed features with the same format and 
    # coordinate reference system as the source.
    with collection(
            "shifted.shp", 
            "w",
            driver=source.driver,
            schema=source.schema,
            crs=source.crs
            ) as sink:

        for rec in source:
            try:
                g = rec['geometry']
                g['coordinates'] = shifters[g['type']](
                    g['coordinates'], delta )
                rec['geometry'] = g
                sink.write(rec)
            except Exception, e:
                log.exception("Error processing record %s:", rec)

Оновлення : я розмістив іншу, більш жорстку версію цього сценарію на веб-сайті http://sgillies.net/blog/1128/geoprocessing-for-hipsters-translating-features .


2
"Геообробка для хіпстерів" Я хотів би, щоб я міг просто підкреслити 10 разів за цей дивовижний заголовок
Рагі Ясер Бурхум

13

І хоча повідомлення позначено python, оскільки JEQL вже згадувалося, ось приклад із JavaScript (за допомогою GeoScript ).

/**
 * Shift all coords in all features for all layers in some directory
 */

var Directory = require("geoscript/workspace").Directory;
var Layer = require("geoscript/layer").Layer;

// offset for all geometry coords
var dx = dy = 10;

var dir = Directory("./data");
dir.names.forEach(function(name) {
    var orig = dir.get(name);
    var shifted = Layer({
        schema: orig.schema.clone({name: name + "-shifted"})
    });
    orig.features.forEach(function(feature) {
        var clone = feature.clone();
        clone.geometry = feature.geometry.transform({dx: dx, dy: dy});
        shifted.add(clone);
    });
    dir.add(shifted);
});

13

Використовуючи GDAL> = 1.10.0, компільований із SQLite та SpatiaLite:

ogr2ogr data_shifted.shp data.shp -dialect sqlite -sql "SELECT ShiftCoords(geometry,1,10) FROM data"

де shiftX = 1 і shift Y = 10.


1
Блискуче - просте однолінійне рішення CLI.
Дейв X

короткий і легкий!
Курт

8

Модуль GRASS GIS v.edit :

Передбачається наявне розташування та набір карт у відповідній проекції.

У сценарії оболонки:

#!/bin/bash

for file in `ls | grep \.shp$ | sed 's/\.shp$//g'`
do
    v.in.ogr dsn=./${file}.shp output=$file
    v.edit map=$file tool=move move=1,1 where="1=1"
    v.out.ogr input=$file type=point,line,boundary,area dsn=./${file}_edit.shp
done

або в сценарії Python:

#!/usr/bin/env python

import os
from grass.script import core as grass

for file in os.listdir("."):
    if file.endswith(".shp"):
        f = file.replace(".shp","")
        grass.run_command("v.in.ogr", dsn=file, output=f)
        grass.run_command("v.edit", map=f, tool="move", move="1,1", where="1=1")
        grass.run_command("v.out.ogr", input=f, type="point,line,boundary,area", dsn="./%s_moved.shp" % f)

8

Іншим варіантом було б використання параметрів репроекції просто у ogr2ogr, безумовно, більш хакірніший підхід, ніж підходи JEQL, Fiona або GeoScript, але ефективні нічим не менш. Зауважте, що проекції від та до насправді не повинні бути фактичною проекцією оригінального формату файлів до тих пір, поки єдине, що змінюється між проекціями, які використовуються в s_srs та t_srs, - це хибне схід і норверінг. У цьому прикладі я просто використовую Google Mercator. Я впевнений, що в якості основи використовується набагато простіша система координат, але ця була прямо перед мною для копіювання / вставки.

ogr2ogr -s_srs EPSG:900913 -t_srs 'PROJCS["Google Mercator",GEOGCS["WGS 84",DATUM["World Geodetic System 1984",SPHEROID["WGS 84",6378137.0,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0.0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.017453292519943295],AXIS["Geodetic latitude",NORTH],AXIS["Geodetic longitude",EAST],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["semi_minor",6378137.0],PARAMETER["latitude_of_origin",0.0],PARAMETER["central_meridian",0.0],PARAMETER["scale_factor",1.0],PARAMETER["false_easting",1000.0],PARAMETER["false_northing",1000.0],UNIT["m",1.0],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","900913"]]' -f "ESRI Shapefile" shift.shp original.shp

Або щоб зберегти набравши / вставити, збережіть наступне в projcs.txt(те саме, що вище, але видалено з додаванням одинарних лапок):

-s_srs EPSG:900913 -t_srs PROJCS["Google Mercator",GEOGCS["WGS 84",DATUM["World Geodetic System 1984",SPHEROID["WGS 84",6378137.0,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0.0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.017453292519943295],AXIS["Geodetic latitude",NORTH],AXIS["Geodetic longitude",EAST],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["semi_minor",6378137.0],PARAMETER["latitude_of_origin",0.0],PARAMETER["central_meridian",0.0],PARAMETER["scale_factor",1.0],PARAMETER["false_easting",1000.0],PARAMETER["false_northing",1000.0],UNIT["m",1.0],AXIS["Easting",EAST],AXIS["Northing",NORTH],AUTHORITY["EPSG","900913"]]

а потім запустіть:

ogr2ogr --optfile projcs.txt shifted.shp input.shp

2
Це перетворюється на гео-сценарій гольфу! Наступним кроком буде зламати вашу таблицю EPSG, щоб усунути довгі буквальні PROJCS;)
sgillies

@sgillies, не потрібно хакнути epsg, просто збережіть projcs у файл та використовувати --optfile, наприклад ogr2ogr --optfile projcs.txt shifted.shp input.shp. Я складу це у відповідь.
matt wilkie

7

Варіант R з використанням пакунків maptools та його функції elide:

shift.xy <- c(1, 2)
library(maptools)
files <- list.files(pattern = "shp$")
for (fi in files) {
  xx <- readShapeSpatial(fi)
  ## update the geometry with elide arguments
  shifted <- elide(xx, shift = shift.xy)
  ## write out a new shapfile
  writeSpatialShape(shifted, paste("shifted", fi, sep = ""))
}

4

Використовуючи аналізатор формфайлу в геофункціях, ви можете використовувати XSLT для виконання процесу. Звичайно, після цього вам потрібно буде перетворити файли у formfile :-).

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0" xmlns:gml="http://www.opengis.net/gml">
    <xsl:param name="x_shift" select="0.0"/>
    <xsl:param name="y_shift" select="0.0"/>

    <!-- first the identity transform makes sure everything gets copied -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- for any element with coordinate strings, apply the translation factors -->
    <!-- note that a schema-aware processor could use the schema type names to simplify -->
    <xsl:template match="gml:pos|gml:posList|gml:lowerCorner|gml:upperCorner">
        <xsl:copy>
            <!-- this xpath parses the ordinates, assuming x y ordering (shapefiles), applies translation factors -->
            <xsl:value-of select="
                for $i in tokenize(.,'\s+') return 
                  if ($i[(position() mod 2) ne 0]) then 
                    number($i)+$x_shift 
                  else 
                    number($i)+$y_shift
             "/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

4

Ось версія Groovy GeoScript:

import geoscript.workspace.Directory
import geoscript.layer.Layer

int dx = 10
int dy = 10

def dir = new Directory("./data")
dir.layers.each{name ->
    def orig = dir.get(name)
    def shifted = dir.create("${name}-shifted", orig.schema.fields)
    shifted.add(orig.cursor.collect{f ->
        f.geom = f.geom.translate(dx, dy)
        f
    })
}  

0

Ось версія OGR

driver = ogr.GetDriverByName ("ESRI Shapefile")

переміщення def (dx, dy, dz):

dataSource = driver.Open(path,1)
layer = dataSource.GetLayer(0)
for feature in layer:
    get_poly = feature.GetGeometryRef()
    get_ring = get_poly.GetGeometryRef(0)
    points   = get_ring.GetPointCount()
    set_ring = ogr.Geometry(ogr.wkbLinearRing)
    for p in xrange(points):
        x,y,z = get_ring.GetPoint(p)
        x += dx
        y += dy
        z += dz
        set_ring.AddPoint(x,y)
        print x,y,z
set_poly = ogr.Geometry(ogr.wkbPolygon)
set_poly.AddGeometry(set_ring)

feature.SetGeometry(set_poly)
layer.SetFeature(feature)

del layer
del feature
del dataSource   
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.