使用系统点光栅填充3D主体

时间:2016-03-20 14:50:59

标签: r algorithm 3d

我有一套3D体。每个Body由8个点定义,每个点有三个坐标。所有的身体都是立方体或近似立方体。我想"填写"具有系统点光栅的立方体。坐标存储在简单的data.frames中。

我开发了以下代码来完成我想要的立方体:

# libraries
library(rgl)

# define example cube with 8 points
excube <- data.frame(
  x = c(1,1,1,1,5,5,5,5), 
  y = c(1,1,4,4,1,1,4,4), 
  z = c(4,8,4,8,4,8,4,8)
)

# cubeconst: fill cube (defined by 8 corner points) with a 3D-point-raster
cubeconst <- function(x, y, z, res) {
  cube <- data.frame()
  xvec = seq(min(x), max(x), res)
  yvec = seq(min(y), max(y), res)
  zvec = seq(min(z), max(z), res)
  for (xpoint in 1:length(xvec)) {
    for (ypoint in 1:length(yvec)) {
      for (zpoint in 1:length(zvec)) {
        cube <- rbind(cube, c(xvec[xpoint], yvec[ypoint], zvec[zpoint]))
      }
    }
  }
  colnames(cube) <- c("x", "y", "z")
  return(cube)
}

# apply cubeconst to excube
fcube <- cubeconst(x = excube$x, y = excube$y, z = excube$z, res = 0.5)

# plot result
plot3d(
  fcube$x,
  fcube$y,
  fcube$z,
  type = "p", 
  xlab = "x", 
  ylab = "y", 
  zlab = "z"
)

现在我正在寻找一个解决方案来填充&#34;大约立方体,例如下面的身体:

# badcube
badcube <- data.frame(
  x = c(1,1,1,1,5,5,5,5), 
  y = c(1,1,4,4,1,1,4,4), 
  z = c(4,10,4,12,4,8,4,8)
)

# plot badcube
plot3d(
  badcube$x,
  badcube$y,
  badcube$z,
  col = "red",
  size = 10,
  type = "p", 
  xlab = "x", 
  ylab = "y", 
  zlab = "z"
)

也许你可以指出我正确的方向。

2 个答案:

答案 0 :(得分:2)

您需要将六面体(不稳定立方体)转换为单位立方体。下图显示了我的意思,并为我们提供了hexa顶点的编号方案。顶点2隐藏在多维数据集后面。

enter image description here

转换是从真实空间x,y,z到新坐标系u,v,w,其中hexa是一个单位立方体。用于hexa的典型函数如下所示。

x = A + B*u + C*v + D*w + E*u*v + F*u*w + G*v*w + H*u*v*w

y和z坐标的转换具有相同的形式。你的立方体有8个角,所以你可以用这些角来代替系数A,B,...。单位坐标u,v,w在每个顶点都是01,因此这简化了很多事情。

x0 = A                             // everything = zero
x1 = A + B                         // u = 1, others = zero
x2 = A + C                         // v = 1, ...
x4 = A + D                         // w = 1
x3 = A + B + C + E                 // u = v = 1
x5 = A + B + D + F                 // u = w = 1
x6 = A + C + D + G                 // v = w = 1
x7 = A + B + C + D + E + F + G + H // everything = 1

然后你必须解决A,B,...。这很简单,因为你只是转发替补。 A等于x0B等于x1 - A等等......您必须为yz执行此操作,但如果您的语言支持向量操作,则可以在与x相同的步骤。

获得系数后,您可以将点u,v,w转换为x,y,z。现在,如果你有一个适用于1x1x1立方体的点生成方案,你可以将结果转换为原始十六进制。您可以在发布的代码中保留相同的三重循环结构,并在u,v,w0之间改变1,以在十六进制内创建一个点网格。

我害怕我不知道r,所以我不能用这种语言给你任何示例代码。这是一个快速的python3示例,只是为了证明它有效。

import matplotlib.pyplot as pp
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

np.random.seed(0)

cube = np.array([
    [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0],
    [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0], [1.0, 1.0, 1.0]])

hexa = cube + 0.5*np.random.random(cube.shape)

edges = np.array([
    [0, 1], [0, 2], [1, 3], [2, 3],
    [0, 4], [1, 5], [2, 6], [3, 7],
    [4, 5], [4, 6], [5, 7], [6, 7]])

def cubeToHexa(hexa, u, v, w):
    A = hexa[0]
    B = hexa[1] - A
    C = hexa[2] - A
    D = hexa[4] - A
    E = hexa[3] - A - B - C
    F = hexa[5] - A - B - D
    G = hexa[6] - A - C - D
    H = hexa[7] - A - B - C - D - E - F - G
    xyz = (
            A +
            B*u[...,np.newaxis] +
            C*v[...,np.newaxis] +
            D*w[...,np.newaxis] +
            E*u[...,np.newaxis]*v[...,np.newaxis] +
            F*u[...,np.newaxis]*w[...,np.newaxis] +
            G*v[...,np.newaxis]*w[...,np.newaxis] +
            H*u[...,np.newaxis]*v[...,np.newaxis]*w[...,np.newaxis])
    return xyz[...,0], xyz[...,1], xyz[...,2]

fg = pp.figure()
ax = fg.add_subplot(111, projection='3d')

temp = np.reshape(np.append(hexa[edges], np.nan*np.ones((12,1,3)), axis=1), (36,3))
ax.plot(temp[:,0], temp[:,1], temp[:,2], 'o-')

u, v, w = np.meshgrid(*[np.linspace(0, 1, 6)]*3)
x, y, z = cubeToHexa(hexa, u, v, w)
ax.plot(x.flatten(), y.flatten(), z.flatten(), 'o')

pp.show()

我不记得这种形式的转变的确切辩解。它当然很容易解决,并且它没有平方项,因此u,v,w轴方向的线条映射到x,y,z中的直线。这意味着您的立方体边和面保证一致,以及角落。但是,我缺乏证明它的数学,而且我也找不到任何可谷歌信息。我的知识来自对有限元方法的教科书的遥远记忆,其中这些变换是常见的。如果您需要更多信息,我建议您开始寻找。

答案 1 :(得分:1)

感谢Bills的解释和示例,我能够在R中提出以下解决方案:

# libraries
library(rgl)

# create heavily distorted cube - hexahedron
hexatest <- data.frame(
  x = c(0,1,0,4,5,5,5,5), 
  y = c(1,1,4,4,1,1,4,4), 
  z = c(4,8,4,9,4,8,4,6)
)

# cubetohexa: Fills hexahedrons with a systematic point raster
cubetohexa <- function(hexa, res){

  # create new coordinate system (u,v,w)
  resvec <- seq(0, 1, res)
  lres <- length(resvec)

  u <- c()
  for (p1 in 1:lres) {
    u2 <- c()
    for (p2 in 1:lres) {
      u2 <- c(u2, rep(resvec[p2], lres))
    }
    u <- c(u,u2)
  }

  v <- c()
  for (p1 in 1:lres) {
    v <- c(v, rep(resvec[p1], lres^2))
  }

  w <- rep(resvec, lres^2)

  # transformation
  A <- as.numeric(hexa[1,])
  B <- as.numeric(hexa[2,]) - A
  C <- as.numeric(hexa[3,]) - A
  D <- as.numeric(hexa[5,]) - A
  E <- as.numeric(hexa[4,]) - A - B - C
  F <- as.numeric(hexa[6,]) - A - B - D
  G <- as.numeric(hexa[7,]) - A - C - D
  H <- as.numeric(hexa[8,]) - A - B - C - D - E - F - G

  A <- matrix(A, ncol = 3, nrow = lres^3, byrow = TRUE)
  B <- matrix(B, ncol = 3, nrow = lres^3, byrow = TRUE)
  C <- matrix(C, ncol = 3, nrow = lres^3, byrow = TRUE)
  D <- matrix(D, ncol = 3, nrow = lres^3, byrow = TRUE)
  E <- matrix(E, ncol = 3, nrow = lres^3, byrow = TRUE)
  F <- matrix(F, ncol = 3, nrow = lres^3, byrow = TRUE)
  G <- matrix(G, ncol = 3, nrow = lres^3, byrow = TRUE)
  H <- matrix(H, ncol = 3, nrow = lres^3, byrow = TRUE)

  for (i in 1:(lres^3)) {
    B[i,] <- B[i,] * u[i]
    C[i,] <- C[i,] * v[i]
    D[i,] <- D[i,] * w[i]
    E[i,] <- E[i,] * u[i] * v[i]
    F[i,] <- F[i,] * u[i] * w[i]
    G[i,] <- G[i,] * v[i] * w[i]
    H[i,] <- H[i,] * u[i] * v[i] * w[i]
  }

  m <- data.frame(A+B+C+D+E+F+G+H)
  colnames(m) <- c("x", "y", "z")

  # output
  return(m)
}

# apply cubetohexa to hexatest
cx <- cubetohexa(hexatest, 0.1)

# plot result
plot3d(
  cx$x,
  cx$y,
  cx$z,
  type = "p", 
  xlab = "x", 
  ylab = "y", 
  zlab = "z"
)

修改

此功能现在在我的R包recexcavAAR中使用Rcpp实现。