简体   繁体   中英

Detect if a LineString / MultiLineString is inside a Polygon or if it intersects it using JTS library

Description

So basically what I would like to know is whether a LineString (or MultiLineString ) is contained in a MultiPolygon or if it intersects it.

I'm not entirely sure that it might affect, but the real case scenario is that I have a LineString that represents a hiking track, and I need to know through which world areas (which would be my MultiPolygon s) is that track going through. Or in the case it is inside of one of my world areas, I need to know which area is containing that LineString .

My problem

My issue here is that I'm getting false positives . If I perform the same check with a Point (to see if it is contained in a MultiPolygon ), instead of a LineString , it works perfectly fine.

Steps to accomplish my goal:

  1. Process my LineString from EPSG 3857 format to EPSG 4326 format (using this formula Converting coordinates from EPSG 3857 to 4326 DotSpatial ), since the LineString I received it was in the EPSG 3857 format.
  2. Read my Geometries (using Gson and JtsAdapter , since they are in GeoJson format, concretely they are MultiPolygon s). This point shouldn't be the problem, since I use it to detect if a Point is inside a Polygon somewhere else, and works totally OK.
  3. Check whether my LineString intersects or is contained by any of the MultiPolygon s and register all the IDs of this MultiPolygon s.

My code:

1.Convert my LineString from EPSG 3857 to EPSG 4326:

private fun reprojectFromEpsg3857ToEpsg4326(geometry: Geometry): Geometry
{
    val e = 2.7182818284
    val X = 20037508.34

    if (geometry is LineString) {
        for (i in 0 until geometry.numPoints) {
            val coordinate = geometry.getCoordinateN(i)
            geometry.getCoordinateN(i).x = (coordinate.x * 180) / X
            geometry.getCoordinateN(i).y = coordinate.y / (X / 180)
            geometry.getCoordinateN(i).y = ((Math.atan(Math.pow(e, ((PI / 180) * geometry.getCoordinateN(i).y)))) / (PI / 360)) - 90
        }
    } else if (geometry is MultiLineString) {
        try {
            for (i in 0 until geometry.numGeometries) {
                for (j in 0 until geometry.getGeometryN(i).coordinates.size) {
                    val coordinate = geometry.getGeometryN(i).coordinates[i]
                    geometry.getGeometryN(i).coordinates[i].x = (coordinate.x * 180) / X
                    geometry.getGeometryN(i).coordinates[i].y = coordinate.y / (X / 180)
                    geometry.getGeometryN(i).coordinates[i].y = ((Math.atan(Math.pow(e,((PI / 180) * geometry.getGeometryN(i).coordinates[i].y)))) / (PI / 360)) - 90
                }
            }
        } catch (e: ArrayIndexOutOfBoundsException) {

        }
    }

    return geometry
}

2.Read my Geometries using Gson and Jts adapter:

private fun getGeometries(gson: Gson): HashMap<Long, Geometry>
{
    val geoJsonGeometries = HashMap<Long, Geometry>()
    val geometriesFolder = File("geometries-folder")

    geometriesFolder.listFiles(getFilenameFilter("geojson")).forEach {
        val reader = FileReader(it)
        var geometry = gson.fromJson(reader, Geometry::class.java)

        if (geometry.geometryType == "GeometryCollection") {
            geometry = geometry.getGeometryN(0)
        }

        val geometryId = java.lang.Long.parseLong(it.name.replace(".geojson", ""))
        geoJsonGeometries[geometryId] = geometry
    }

    return geoJsonGeometries
}

3.Perform the check to see which MultiPolygon s are related (either by containment or by intersection) with my LineString :

val geometryIds = ArrayList<Long>()
geometries.forEach { geometryId, mapBoundaries ->
    if (routeAsLineString.intersects(mapBoundaries) || mapBoundaries.contains(routeAsLineString)) {
        geometryIds.add(geometryId)
    }
}

Any help would be very thankful!

Alright, I got very wrongly the MultiLineString conversion from EPSG 3857 format to EPSG 4326 format. Basically, I wasn't converting the MultiLineString , only the first coordinate was being converted. But there are many Geometry objectes inside a MultiLineString and each of them has many coordinates.

So steps 2 and 3 were correct.

The original conversion was:

for (i in 0 until geometry.numGeometries) {
    for (j in 0 until geometry.getGeometryN(i).coordinates.size) {
        val coordinate = geometry.getGeometryN(i).coordinates[i]
        geometry.getGeometryN(i).coordinates[i].x = (coordinate.x * 180) / X
        geometry.getGeometryN(i).coordinates[i].y = coordinate.y / (X / 180)
        geometry.getGeometryN(i).coordinates[i].y = ((Math.atan(Math.pow(e,((PI / 180) * geometry.getGeometryN(i).coordinates[i].y)))) / (PI / 360)) - 90
    }
}

But should have been:

for (i in 0 until geometry.numGeometries) {
    for (j in 0 until geometry.getGeometryN(i).coordinates.size) {
        val coordinate = geometry.getGeometryN(i).coordinates[j]
        geometry.getGeometryN(i).coordinates[j].x = (coordinate.x * 180) / X
        geometry.getGeometryN(i).coordinates[j].y = coordinate.y / (X / 180)
        geometry.getGeometryN(i).coordinates[j].y = ((Math.atan(Math.pow(e,((PI / 180) * geometry.getGeometryN(i).coordinates[j].y)))) / (PI / 360)) - 90
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM