gpt4 book ai didi

Java地理工具: Snap to line identifiying line that was snapped to

转载 作者:太空宇宙 更新时间:2023-11-04 11:53:26 25 4
gpt4 key购买 nike

我正在尝试编写一个 Java 程序,它将大量 GPS 坐标捕捉到线形文件(道路网络),并且不仅返回新坐标,还返回捕捉到的线段的唯一标识符。该标识符是否是 FID、其他语言中使用的“索引”(即,其中 1 是第一个特征等)或属性表中的任何列都无关紧要。

我在 R 中使用 maptools::snapPointsToLines 完成了此操作函数,但考虑到我需要处理的数据量,这是不可扩展的,因此我正在寻找 Java 来更快地处理数据,以便在 R 中进行分析。

我的代码(如下)目前与用于捕捉的 geotools 教程非常相似,其中的细微差别是我在 GPS 点的(1900 万行)CSV 中读取而不是生成它们,并编写了结果的 CSV。它捕捉得很好,而且比我得到的要快得多,但我不知道如何识别捕捉到的线。可用的文档似乎涵盖了功能集的查询和过滤,我无法特别适用于此代码创建的索引行对象,并且我的代码中的现有函数 toString() 返回一些对于我的目的而言难以理解的内容,例如 com.vividsolutions.jts.linearreff.LocationIndexedLine@74cec793

基本上,我只是希望 lineID 字段生成任何其他 GIS 软件或语言都可以与特定路段匹配的内容。

package org.geotools.tutorial.quickstart;

import java.io.*;
import java.util.List;
import java.util.Arrays;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.index.SpatialIndex;
import com.vividsolutions.jts.index.strtree.STRtree;
import com.vividsolutions.jts.linearref.LinearLocation;
import com.vividsolutions.jts.linearref.LocationIndexedLine;

import org.geotools.data.FeatureSource;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.swing.data.JFileDataStoreChooser;
import org.geotools.util.NullProgressListener;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureVisitor;
import org.opengis.feature.simple.SimpleFeature;
import com.opencsv.*;

public class SnapToLine {

public static void main(String[] args) throws Exception {

/*
* Open a shapefile. You should choose one with line features
* (LineString or MultiLineString geometry)
*
*/
File file = JFileDataStoreChooser.showOpenFile("shp", null);
if (file == null) {
return;
}

FileDataStore store = FileDataStoreFinder.getDataStore(file);
FeatureSource source = store.getFeatureSource();

// Check that we have line features
Class<?> geomBinding = source.getSchema().getGeometryDescriptor().getType().getBinding();
boolean isLine = geomBinding != null
&& (LineString.class.isAssignableFrom(geomBinding) ||
MultiLineString.class.isAssignableFrom(geomBinding));

if (!isLine) {
System.out.println("This example needs a shapefile with line features");
return;
}
final SpatialIndex index = new STRtree();
FeatureCollection features = source.getFeatures();
//FeatureCollection featurecollection = source.getFeatures(Query.FIDS);
System.out.println("Slurping in features ...");
features.accepts(new FeatureVisitor() {

@Override
public void visit(Feature feature) {
SimpleFeature simpleFeature = (SimpleFeature) feature;
Geometry geom = (MultiLineString) simpleFeature.getDefaultGeometry();
// Just in case: check for null or empty geometry
if (geom != null) {
Envelope env = geom.getEnvelopeInternal();
if (!env.isNull()) {
index.insert(env, new LocationIndexedLine(geom));
}
}
}
}, new NullProgressListener());
/*

/*
* We defined the maximum distance that a line can be from a point
* to be a candidate for snapping
*/

ReferencedEnvelope bounds = features.getBounds();
final double MAX_SEARCH_DISTANCE = bounds.getSpan(0) / 1000.0;



int pointsProcessed = 0;
int pointsSnapped = 0;
long elapsedTime = 0;
long startTime = System.currentTimeMillis();
double longiOut;
double latiOut;
int moved;
String lineID = "NA";

//Open up the CSVReader. Reading in line by line to avoid memory failure.

CSVReader csvReader = new CSVReader(new FileReader(new File("fakedata.csv")));
String[] rowIn;



//open up the CSVwriter
String outcsv = "fakedataOUT.csv";
CSVWriter writer = new CSVWriter(new FileWriter(outcsv));



while ((rowIn = csvReader.readNext()) != null) {

// Get point and create search envelope
pointsProcessed++;
double longi = Double.parseDouble(rowIn[0]);
double lati = Double.parseDouble(rowIn[1]);
Coordinate pt = new Coordinate(longi, lati);
Envelope search = new Envelope(pt);
search.expandBy(MAX_SEARCH_DISTANCE);

/*
* Query the spatial index for objects within the search envelope.
* Note that this just compares the point envelope to the line envelopes
* so it is possible that the point is actually more distant than
* MAX_SEARCH_DISTANCE from a line.
*/
List<LocationIndexedLine> lines = index.query(search);

// Initialize the minimum distance found to our maximum acceptable
// distance plus a little bit
double minDist = MAX_SEARCH_DISTANCE + 1.0e-6;
Coordinate minDistPoint = null;

for (LocationIndexedLine line : lines) {
LinearLocation here = line.project(pt);
Coordinate point = line.extractPoint(here);
double dist = point.distance(pt);
if (dist < minDist) {
minDist = dist;
minDistPoint = point;
lineID = line.toString();
}
}


if (minDistPoint == null) {
// No line close enough to snap the point to
System.out.println(pt + "- X");
longiOut = longi;
latiOut = lati;
moved = 0;
lineID = "NA";
} else {
System.out.printf("%s - snapped by moving %.4f\n",
pt.toString(), minDist);
longiOut = minDistPoint.x;
latiOut = minDistPoint.y;
moved = 1;
pointsSnapped++;
}
//write a new row

String [] rowOut = {Double.toString(longiOut), Double.toString(latiOut), Integer.toString(moved), lineID};
writer.writeNext(rowOut);
}

System.out.printf("Processed %d points (%.2f points per second). \n"
+ "Snapped %d points.\n\n",
pointsProcessed,
1000.0 * pointsProcessed / elapsedTime,
pointsSnapped);
writer.close();
}
}

我不仅是 Java 新手,而且只是在领域特定语言(如 R)方面进行了自学;我与其说是一个编码员,不如说是一个使用代码的人,所以如果解决方案看起来很明显,我可能缺乏基本理论!

p.s 我知道有更好的 map 匹配解决方案(graphhopper 等),我只是想开始 eas!

谢谢!

最佳答案

我会尽量避免在 JTS 兔子洞中走得太远,并坚持使用 GeoTools(当然我是一个 GeoTools 开发人员,所以我会这么说)。

首先我会使用SpatialIndexFeatureCollection保存我的行(假设它们适合内存,否则 PostGIS 表是可行的方法)。这使我不必建立自己的索引。

然后我会使用CSVDataStore避免从 GPS 流中解析我自己的点(因为我很懒,而且那里也有很多出错的地方)。

这意味着大部分工作都归结为这个循环,DWITHIN 查找指定距离内的所有要素:

try (SimpleFeatureIterator itr = pointFeatures.getFeatures().features()) { 
while (itr.hasNext()) {
SimpleFeature f = itr.next();
Geometry snapee = (Geometry) f.getDefaultGeometry();
Filter filter = ECQL.toFilter("DWITH(\"the_geom\",'" + writer.write(snapee) + "'," + MAX_SEARCH_DISTANCE + ")");
SimpleFeatureCollection possibles = indexed.subCollection(filter);
double minDist = Double.POSITIVE_INFINITY;
SimpleFeature bestFit = null;
Coordinate bestPoint = null;
try (SimpleFeatureIterator pItr = possibles.features()) {
while (pItr.hasNext()) {
SimpleFeature p = pItr.next();
Geometry line = (Geometry) p.getDefaultGeometry();

double dist = snapee.distance(line);
if (dist < minDist) {
minDist = dist;
bestPoint = DistanceOp.nearestPoints(snapee, line)[1];
bestFit = p;
}
}
}

在循环结束时,您应该知道距离线最近的特征(bestFit)(包括其 ID 和名称等)、最近的点(bestPoint)和移动的距离(minDist)。

我可能也会使用 CSVDatastore 将功能写回。

如果您有数百万个点,我可能会考虑使用 FilterFactory 直接创建过滤器,而不是使用 ECQL 解析器。

关于Java地理工具: Snap to line identifiying line that was snapped to,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41580197/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com