Search code examples
rcartesian-coordinates

Generate 3D Cartesian Surface Coordinates using n dimensions


I've implemented some code to generate a 3D Cartesian coordinate surface using specified dimensions. However, this is rather slow and a very inefficient way to implement this. Could someone help me with a better method that requires less iterations?

library(rgl)
density <- 1

#test data 5 x 10 x 15 box
a <- seq(from = 1, to = 5, by = density)
b <- seq(from = 1, to = 10, by = density)
c <- seq(from = 1, to = 15, by = density)

#length of each dimension
aL <- length(a)
bL <- length(b)
cL <- length(c)

#data.frame to store 3D box
test = data.frame()

#calculate the indices for the nested for loop
inner <- bL * cL
outer <- aL * bL * cL
tracker <- 1:inner
tracker <- c(tracker, (outer - (inner) + 1):outer)
for(x in 1:(aL-2)) {
    for(i in 1:bL) {
        if(i == 1 || i == bL) {
            tracker <- c(tracker, (inner+1):(inner+cL))
        } else {
            tracker <- c(tracker, inner + 1)
            tracker <- c(tracker, inner + cL)
        }
        inner <- inner + cL
    }
}

#loops over all possible combinations and uses only the indices above
iter <- 1
for(x in a) {
    for(y in b) {
        for(z in c) {
            if(any(iter == tracker)) {
                test <- rbind(test, data.frame(x = x, y = y, z = z))
            }
            iter <- iter + 1
        }
    }
}

points3d(test)

Solution

  • While there are opportunities to speed this up by pre-allocating vectors and data frames, have you considered generating the six faces of your surface separately, and then sticking them together?

    The expand.grid function makes this easy:

    faces_xy <- expand.grid(x = a, y = b, z = c(min(c), max(c)))
    faces_xz <- expand.grid(x = a, y = c(min(b), max(b)), z = c)
    faces_yz <- expand.grid(x = c(min(a), max(a)), y = b, z = c)
    surface <- unique(rbind(faces_xy, faces_xz, faces_yz))
    

    Each of the faces_ variables contains the two faces on the specified plane. The call to unique is to eliminate duplicate points on edges shared by faces.

    I haven't done any benchmarking or bothered to analyse the complexity of each approach, but I would expect this to be significantly faster.