Làm thế nào để dễ dàng thay đổi tất cả các tính năng trong một tập dữ liệu vector?


33

Giả sử tôi kết hợp một Shapefile và tất cả các tính năng có các đỉnh của chúng bị dịch chuyển bởi một lượng không đổi. Cách dễ nhất để dịch chuyển tất cả các tính năng (do đó vị trí (x, y) của các đỉnh của chúng) bằng một dịch chuyển tùy ý là gì? Tôi có rất nhiều tệp mà tôi sẽ áp dụng hiệu chỉnh này, vì vậy câu trả lời Bash / OGR sẽ được ưu tiên :)

Cuối cùng, tôi đã kết thúc việc sử dụng Spatialite cho việc này, vì nó có chức năng tốt ShiftCoords. Tuy nhiên, chủ đề rất nhiều thông tin! Cảm ơn tất cả!


Tôi chỉ thích mục này. Toàn bộ trang này là một ví dụ tuyệt vời về hỏi đáp đã đúng. Một câu hỏi được mô tả rõ ràng đơn giản và mỗi câu trả lời đưa ra một giải pháp duy nhất, hợp lệ và đầy đủ. Nó thật đẹp. Tôi ủng hộ từng người một, mỗi người về giá trị riêng của họ.
matt wilkie

@Jose Bài đăng này cần một bản cập nhật nhỏ do những cải tiến tương đối gần đây của thư viện GDAL. Có một giải pháp lót ngay bây giờ (xem câu trả lời dưới đây)! Có thể sử dụng trực tiếp chức năng SpCoiaLite ShiftCoords với tiện ích ogr2ogr.
Antonio Falciano

Câu trả lời:


21

Sử dụng JEQL Điều này có thể được thực hiện với ba dòng:

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

cắt cạnh! tốt đẹp!
WolfOdrade

Hay đấy, David. Nó chặt quá.
sgillies

1
Chỉ cần chỉ ra ... "ahapefile?"
WolfOdrade

Tôi đã kết thúc bằng cách sử dụng chức năng dịch của Spatialite, tương tự như những gì bạn đề xuất ở đây.
Jose

30

Tôi đã thiết kế Fiona (một trình bao bọc OGR) để làm cho kiểu xử lý này trở nên đơn giản.

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)

Cập nhật : Tôi đã đặt một phiên bản khác, chặt chẽ hơn của tập lệnh này tại http://sgillies.net/blog/1128/geoprocessing-for-hipsters-translating-features .


2
"Geoprocessing for hipster" Tôi ước tôi có thể nâng cấp gấp 10 lần cho danh hiệu tuyệt vời đó
Ragi Yaser Burhum

13

Và mặc dù bài đăng được gắn thẻ python, vì JEQL đã được đề cập, đây là một ví dụ với JavaScript (sử dụng 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

Sử dụng GDAL> = 1.10.0 được biên dịch bằng SQLite và SpatiaLite:

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

trong đó shiftX = 1 và shiftY = 10.


1
Brilliant - một giải pháp CLI một dòng đơn giản.
Dave X

ngắn gọn và dễ dàng
Kurt

8

Mô-đun GRASS GIS v.edit :

Một vị trí và mapset hiện có trong phép chiếu phù hợp được giả định.

Trong tập lệnh shell:

#!/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

hoặc trong tập lệnh 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

Một tùy chọn khác là sử dụng các tùy chọn từ chối đơn giản trong ogr2ogr, chắc chắn là một cách tiếp cận tin tặc hơn các cách tiếp cận JEQL, Fiona hoặc GeoScript nhưng hiệu quả không kém. Lưu ý rằng các phép chiếu từ và tới không thực sự cần phải là hình chiếu thực tế của shapefile ban đầu, miễn là điều duy nhất đang thay đổi giữa các phép chiếu được sử dụng trong s_srs và t_srs là hướng đông và hướng sai. Trong ví dụ này tôi chỉ sử dụng Google Mercator. Tôi chắc chắn có một hệ thống tọa độ đơn giản hơn nhiều để sử dụng làm cơ sở, nhưng hệ thống này đã ở ngay trước mặt tôi để sao chép / dán.

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

Hoặc để lưu gõ / dán, hãy lưu các mục sau vào projcs.txt(giống như trên, nhưng loại bỏ các dấu ngoặc đơn kèm theo):

-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"]]

và sau đó chạy:

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

2
Nó đang biến thành sân golf kịch bản địa lý! Bước tiếp theo sẽ là hack bảng EPSG của bạn để loại bỏ PROJCS theo nghĩa đen dài;)
sgillies

@sgillies, không cần hack epsg, chỉ cần lưu các projcs vào một tệp và sử dụng --optfile, ví dụ ogr2ogr --optfile projcs.txt shifted.shp input.shp. Tôi sẽ gấp nó vào câu trả lời.
matt wilkie

7

Một tùy chọn R sử dụng gói maptools và chức năng elide của nó:

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

Sử dụng trình phân tích cú pháp shapefile trong các hàm địa lý, bạn có thể sử dụng XSLT để thực hiện quy trình. Tất nhiên bạn sẽ cần phải chuyển đổi trở lại shapefile sau đó :-).

<?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

Đây là phiên bản 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

Đây là phiên bản OGR

trình điều khiển = ogr.GetDriverByName ("ESRI Shapefile")

di chuyển 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   
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.