交互式识别 rgl 图中的 3D 对象

Interactively identify 3D object in rgl plot

我想在 rgl 图中识别 3d 圆柱体以获得最近/选定圆柱体的一个属性。我尝试使用标签简单地拼出属性,但我处理的数据超过 10.000 个圆柱体。因此,它变得如此拥挤以致于标签不可读并且需要很长时间才能呈现。

我试图了解 rgl 的文档,我想我的问题的解决方案是手动选择绘图中的圆柱体。我相信函数 selectpoints3d() 可能是要走的路。我相信 returns 绘制矩形内的所有顶点,但我不知道如何返回圆柱数据?我可以计算出哪个圆柱体最接近所选顶点的平均值,但这似乎是一种“快速而肮脏”的工作方式。

有更好的方法吗?我注意到参数 value=FALSE 只获取索引,但我不知道如何返回到圆柱体。

这是一些虚拟数据和我的代码:

# dummy data
cylinder <- data.frame(
  start_X = rep(1:3, 2)*2,
  start_Y = rep(1:2, each = 3)*2,
  start_Z = 0,
  end_X = rep(1:3, 2)*2 + round(runif(6, -1, 1), 2),
  end_Y = rep(1:2, each = 3)*2 + round(runif(6, -1, 1), 2),
  end_Z = 0.5,
  radius = 0.25,
  attribute = sample(letters[1:6], 6)
)

# calculate centers
cylinder$center_X <- rowMeans(cylinder[,c("start_X", "end_X")])
cylinder$center_Y <- rowMeans(cylinder[,c("start_Y", "end_Y")])
cylinder$center_Z <- rowMeans(cylinder[,c("start_Z", "end_Z")])

# create cylinders
cylinder_list <- list()
for (i in 1:nrow(cylinder)) {
  cylinder_list[[i]] <- cylinder3d(
    center = cbind(
      c(cylinder$start_X[i], cylinder$end_X[i]),
      c(cylinder$start_Y[i], cylinder$end_Y[i]),
      c(cylinder$start_Z[i], cylinder$end_Z[i])),
    radius = cylinder$radius[i],
    closed = -2)
}

# plot cylinders
open3d()
par3d()
shade3d(shapelist3d(cylinder_list, plot = FALSE), col = "blue")
text3d(cylinder$center_X+0.5, cylinder$center_Y+0.5, cylinder$center_Z+0.5, cylinder$attribute, color="red")

# get attribute
nearby <- selectpoints3d(value=TRUE, button = "right")
nearby <- colMeans(nearby)
cylinder$dist <- sqrt(
  (nearby["x"]-cylinder$center_X)**2 +
  (nearby["y"]-cylinder$center_Y)**2 +
  (nearby["z"]-cylinder$center_Z)**2)
cylinder$attribute[which.min(cylinder$dist)]

如果您调用 selectpoints3d(value = FALSE),您会得到两列。第一列是找到的对象的 ID。您的圆柱体各有两个 ID。标记气缸的一种方法是使用“标签”。比如你的代码这样修改:

# dummy data
cylinder <- data.frame(
  start_X = rep(1:3, 2)*2,
  start_Y = rep(1:2, each = 3)*2,
  start_Z = 0,
  end_X = rep(1:3, 2)*2 + round(runif(6, -1, 1), 2),
  end_Y = rep(1:2, each = 3)*2 + round(runif(6, -1, 1), 2),
  end_Z = 0.5,
  radius = 0.25,
  attribute = sample(letters[1:6], 6)
)

# calculate centers
cylinder$center_X <- rowMeans(cylinder[,c("start_X", "end_X")])
cylinder$center_Y <- rowMeans(cylinder[,c("start_Y", "end_Y")])
cylinder$center_Z <- rowMeans(cylinder[,c("start_Z", "end_Z")])

# create cylinders
cylinder_list <- list()
for (i in 1:nrow(cylinder)) {
  cylinder_list[[i]] <- cylinder3d(
    center = cbind(
      c(cylinder$start_X[i], cylinder$end_X[i]),
      c(cylinder$start_Y[i], cylinder$end_Y[i]),
      c(cylinder$start_Z[i], cylinder$end_Z[i])),
    radius = cylinder$radius[i],
    closed = -2)

  # Add tag here:

  cylinder_list[[i]]$material$tag <- cylinder$attribute[i]
}

# plot cylinders
open3d()
par3d()
shade3d(shapelist3d(cylinder_list, plot = FALSE), col = "blue")
text3d(cylinder$center_X+0.5, cylinder$center_Y+0.5, cylinder$center_Z+0.5, cylinder$attribute, color="red")

# Don't get values, get the ids

nearby <- selectpoints3d(value=FALSE, button = "right", closest = FALSE)
ids <- nearby[, "id"]

# Convert them to tags.  If you select one of the labels, you'll get
# a blank in the list of tags, because we didn't tag the text.

unique(tagged3d(id = ids))

当我尝试这样做时,我发现在 selectpoints3d 中使用 closest = TRUE 似乎得到了太多的 id;那里可能有错误。