草庐IT

r sf 包质心在多边形内

codeneng 2023-03-28 原文

r sf package centroid within polygon

我需要为多边形添加标签,我通常使用质心,但是质心不会落在多边形内。我发现了这个问题 Calculate Centroid WITHIN / INSIDE a SpatialPolygon 但我使用的是 sf 包。

下面是玩具数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
rm(list = ls(all = TRUE)) #start with empty workspace

library(sf)
library(tidyverse)
library(ggrepel)

pol <- st_polygon(list(rbind(c(144, 655),c(115, 666)
                         ,c(97, 660),c(86, 640)
                         ,c(83, 610),c(97, 583)
                         ,c(154, 578),c(140, 560)
                         ,c(72, 566),c(59, 600)
                         ,c(65, 634),c(86, 678)
                         ,c(145, 678),c(144, 655)))) %>%
  st_sfc()

a = data.frame(NAME ="A")
st_geometry(a) = pol

a <- a  %>%
  mutate(lon = map_dbl(geometry, ~st_centroid(.x)[[1]]),
     lat = map_dbl(geometry, ~st_centroid(.x)[[2]]))

ggplot() +
  geom_sf(data = a, fill ="orange") +
  geom_label_repel(data = a, aes(x = lon, y = lat, label = NAME))

导致以下

  • 您可以将 ~st_centroid 替换为 ~st_point_on_surface。也就是说,如果您不关心任何多边形上的真实质心。
  • 这个问题有更多关于 postgis gis.stackexchange.com/questions/76498/... st_PointOnSurface 的信息。


简单的答案是将st_centroid 替换为st_point_on_surface。如果质心位于多边形内部,这将不会返回真正的质心。

1
2
3
4
5
6
7
a2 <- a  %>%
  mutate(lon = map_dbl(geometry, ~st_point_on_surface(.x)[[1]]),
         lat = map_dbl(geometry, ~st_point_on_surface(.x)[[2]]))

ggplot() +
  ggplot2::geom_sf(data = a2, fill ="orange") +
  geom_label_repel(data = a2, aes(x = lon, y = lat, label = NAME))

或者

如果多边形的质心在多边形内,则使用它,否则,在多边形内找到一个点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
st_centroid_within_poly <- function (poly) {

  # check if centroid is in polygon
  centroid <- poly %>% st_centroid()
  in_poly <- st_within(centroid, poly, sparse = F)[[1]]

  # if it is, return that centroid
  if (in_poly) return(centroid)

  # if not, calculate a point on the surface and return that
  centroid_in_poly <- st_point_on_surface(poly)
  return(centroid_in_poly)
}

a3 <- a  %>%
  mutate(lon = map_dbl(geometry, ~st_centroid_within_poly(.x)[[1]]),
         lat = map_dbl(geometry, ~st_centroid_within_poly(.x)[[2]]))

ggplot() +
  ggplot2::geom_sf(data = a3, fill ="orange") +
  geom_label_repel(data = a3, aes(x = lon, y = lat, label = NAME))

st_centroid_within_polygon 上面的函数改编自您为 sf 包引用的问题。可以在此处找到对 st_point_on_surface 工作原理的更全面的回顾。


扩展 Mitch 的答案,因为上面提供的 st_centroid_within_poly 函数仅适用于单个多边形。

要在多个多边形上使用,请使用:

1
2
3
4
5
6
7
8
9
10
11
st_centroid_within_poly <- function (poly) {

  # check if centroid is in polygon
  ctrd <- st_centroid(poly, of_largest_polygon = TRUE)
  in_poly <- diag(st_within(ctrd, poly, sparse = F))

  # replace geometries that are not within polygon with st_point_on_surface()
  st_geometry(ctrd[!in_poly,]) <- st_geometry(st_point_on_surface(poly[!in_poly,]))

  ctrd
}

  • 它在 st_geometry(ctrd[!in_poly,]) <- st_geometry(st_point_on_surface(poly[!in_poly,]))Error in poly[!in_poly, ] : incorrect number of dimensions 失败

有关r sf 包质心在多边形内的更多相关文章

  1. ruby-on-rails - Ruby on Rails PostGIS - 将多边形记录插入数据库 - 2

    我将RoR与PostGIS结合使用来存储位置数据。我正在尝试使用圆(例如,带半径的中心点)来存储估计位置。我试过类似的东西,但它不起作用:@location=Location.new(:place_id=>place.id,:circle=>%{ST_Buffer(ST_MakePoint(#{latitude},#{longitude})::geography,#{accuracy})})我也尝试过使用RGeo,它是出厂设置,但不确定如何准确使用它。任何帮助将不胜感激。谢谢。编辑1:我取得了一些进步。factory=RGeo::Cartesian.factorycenter_poin

  2. ruby-on-rails - 具有六边形架构和 DCI 模式的框架和数据库适配器 - 2

    我尝试用Ruby设计一个基于Web的应用程序。我开发了一个简单的核心应用程序,在没有框架和数据库的情况下在六边形架构中实现DCI范例。核心六边形中有小六边形和网络,数据库,日志等适配器。每个六边形都在没有数据库和框架的情况下自行运行。在这种方法中,我如何提供与数据库模型和实体类的关系作为独立于数据库的关系。我想在将来将框架从Rails更改为Sinatra或数据库。事实上,我如何在这个核心Hexagon中实现完全隔离的rails和mongodb的数据库适配器或框架适配器。有什么想法吗? 最佳答案 ROM呢?(Ruby对象映射器)。还有

  3. sql - Ruby Rails Postgis - 查找多边形中的所有点 - 2

    我需要一些帮助来构建sql查询以在带有activerecord-postgis-adapter的rails中使用。我一直在阅读大量书籍,但现在有点卡住了,非常感谢任何帮助。我有两个模型Events和Areas:事件有一个点类型的“几何”列classEvent{:srid=>4326,:type=>"polygon",:geographic=>true}区域有一个“几何”列,类型为多边形classArea{:srid=>4326,:type=>"point",:geographic=>true}我可以在谷歌地图上创建和绘制事件和区域,并通过点击map并保存到数据库来创建区域。我希望能够执

  4. ruby - 如何在两个六边形字符串之间进行异或运算? - 2

    我有两个十六进制字符串,我需要对它们进行异或操作。我的六弦琴喜欢,a="1A6F2D31567C80644A5BEF2D50B986B";b="EF737F481FC7CDAE7C8B40837C80644";它们之间如何进行异或运算?你能给出一些指导方针吗? 最佳答案 这适用于任何基地:>>(a.to_i(16)^b.to_i(16)).to_s(16)=>"f51c527949bb4dca36d0afae2c39e2f"但是你可以使用String#hex用于十六进制字符串。 关于ru

  5. 如何计算质心 - 2

    如何计算质心原始文档:https://www.yuque.com/lart/idh721/gpbigm概念质心,即质量中心的简称。质点系的质心是质点系质量分布的平均位置。指物质系统上被认为质量集中于此的一个假想点,与重心不同的是质心不一定要在有重力场的系统中,值得注意的是除非重力场是均匀的,否则同一物质系统的质心与重心通常不在同一假想点上。计算质心坐标等于所有点关于每个坐标的以质量为权重的加权平均值。一般主要在二维空间讨论,尤其是图像数据,但是这里直接按照更一般的形式进行定义。首先对于任意nnn维空间中的连续形式的子集PPP的质心可以定义为:C=∫pg(p)dp∫g(p)dpC=\frac{\

  6. javascript - 可以 polygon.setPath();用于完全重新定义多边形? - 2

    GooglemapJavaScriptAPIV3。我的映射让我处理了多边形的概念,在我深入研究代码之前,我试图制定一个策略。我永远不会一次在map上有一个以上的多边形,所以我希望我可以定义一个多边形并像使用标记一样重复使用它。我的理解是否正确,多边形setPath();函数将移动多边形以表示新的点数组?文档说......“从MVCArray插入或删除LatLngs将自动更新map上的多边形。”但它并没有直接说你可以使用setPath();给它一个全新的点阵。我在用伪代码思考...//someeventfirespolygon.setPath(latlngArray);bounds=ne

  7. javascript - 添加一个点以扩展多边形而不将其附加到 Google map 中? - 2

    我正在Googlemap中通过可以拖动以reshape形状的标记构建多边形。因此,当有3个标记时,将绘制多边形,并在形状中附加更多标记,扩展它。当用户只想遵循简单的顺时针/逆时针模式时,这很好,但当他想通过其边缘之一扩展多边形时,它会附加标记,扭曲自身。在此示例中,如果我们添加标记1、2和3,它将绘制一个简单的三Angular形。但是,如果添加标记4,多边形就会自行扭曲。相反,我希望在添加4时将其插入标记1和2之间,如下图所示:基本上,在多边形的顶点数组中,而不是:[//marker1position,//marker2position,//marker3position,//curr

  8. javascript - 使用 Three.js 生成正多边形 - 2

    我正在使用Three.js根据用户提供的边数按程序生成常规N边形。长期目标是将此作为渲染多面体棱镜的第一步。我正在使用讨论的解决方案here计算N边形的顶点。然后我将使用讨论的技术here在N边形上生成面孔。我第一次尝试生成必要的Geometry对象,结果如下,在添加到Mesh后似乎没有渲染任何东西:functioncreateGeometry(n,circumradius){vargeometry=newTHREE.Geometry(),vertices=[],faces=[],x;//Generatetheverticesofthen-gon.for(x=1;x在玩弄它太久之后,我

  9. javascript - 在 Leaflet L.Draw 插件中以编程方式添加多边形 - 2

    有没有办法使用Leaflet绘图插件以编程方式添加多边形?https://github.com/Leaflet/Leaflet.draw例如:点击一个按钮,添加一个可以被插件编辑的正方形。 最佳答案 您只需要将您的多边形(或您想要编辑的任何其他层)添加到您传递给edit.featureGroup的要素组中L.Control.Draw控件的选项。vareditableLayers=L.featureGroup().addTo(map);vardrawControl=newL.Control.Draw({edit:{featureGro

  10. javascript - LatLng 是否在多边形内 - 2

    我在带有一些latLng的谷歌地图上设置了一个典型的多边形:varbermudaTriangle=newgoogle.maps.Polygon({paths:[newgoogle.maps.LatLng(25.774252,-80.190262),newgoogle.maps.LatLng(18.466465,-66.118292),newgoogle.maps.LatLng(32.321384,-64.75737),]});bermudaTriangle.setMap(map);这些是谷歌文档中的百慕大三Angular坐标。我也有一些随机坐标,saaay:varcoord1=newn

随机推荐