2016-03-20 7 views
2

Ich habe eine Reihe von 3D-Bodies. Jeder Körper ist durch 8 Punkte mit jeweils drei Koordinaten definiert. Alle Körper sind kubisch oder annähernd kubisch. Ich möchte die Würfel mit einem systematischen Punktraster "füllen". Die Koordinaten sind in einfachen data.frames gespeichert.Füllen eines 3D-Körpers mit einem systematischen Punkt-Raster

entwickeln ich den folgenden Code, der tut, was ich für kubische Körper will:

# 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" 
) 

Jetzt für eine Lösung, die ich bin auf der Suche den folgenden Körper zu „füllen“ etwa kubischem Körper, wie zum Beispiel:

# 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" 
) 

Vielleicht können Sie mir in die richtige Richtung zeigen.

+0

Könnten Sie bitte erläutern, was Sie mit einem "systematischen Punkt-Raster" meinen? Ich habe deine Frage wie gefragt, wie man einen verzerrten Würfel in NxNxN kleinere Würfel aufteilt. Ist das richtig? – Bill

+0

@Bill Ja ich denke du hast es verstanden. Das Ergebnis des Algorithmus sollte eine Liste von Punkten sein, die innerhalb der Grenzen des verzerrten Würfels liegen. Die Punkte könnten zufällig verteilt sein, aber ich würde es vorziehen, dass sie äquidistant sind. Die Aufteilung in NxNxN kleinere Würfel könnte ein Weg sein, dies zu erreichen. Aber wie? – nevrome

Antwort

2

Sie müssen den Hexaeder (Wonky Cube) in einen Einheitswürfel umwandeln. Das folgende Bild zeigt, was ich meine, und gibt uns ein Nummerierungsschema für die Ecken des Hexa. Vertex 2 ist hinter dem Würfel versteckt.

enter image description here

Die Transformation ist von den realen Raum x,y,z, auf ein neues Koordinatensystem u,v,w, in dem das hexa ein Einheitswürfel ist. Die typische Funktion, die für Hexa verwendet wird, sieht so aus.

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

Transformationen für y- und z-Koordinaten haben die gleiche Form. Sie haben 8 Ecken zu Ihrem Würfel, also können Sie diese ersetzen, um Koeffizienten A,B,... zu lösen. Die Einheitskoordinaten u,v,w sind entweder 0 oder 1 an jedem Scheitelpunkt, so dass dies die Dinge sehr vereinfacht.

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 

Sie müssen dann für A,B,... lösen. Dies ist einfach, weil Sie nur Ersatz austauschen. A entspricht x0. B entspricht x1 - A, etc ... Sie müssen dies für y und z auch tun, aber wenn Ihre Sprache Vektoroperationen unterstützt, kann dies wahrscheinlich in dem gleichen Schritt wie für x getan werden. Wenn Sie die Koeffizienten haben, können Sie einen Punkt u,v,w in x,y,z konvertieren. Wenn Sie jetzt ein Punktgenerierungsschema haben, das auf einem 1x1x1-Würfel funktioniert, können Sie das Ergebnis in das ursprüngliche Hex transformieren. Sie könnten die gleiche Triple-Loop-Struktur in Ihrem geposteten Code beibehalten und u,v,w zwischen 0 und 1 variieren, um ein Raster von Punkten innerhalb des Hex zu erstellen.

Ich fürchte, ich weiß nicht r, so kann ich Ihnen keinen Beispielcode in dieser Sprache geben. Hier ist ein schnelles python3 Beispiel, nur um zu beweisen, dass es funktioniert.

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() 

Ich kann nicht die genaue justificiation für diese Form der Transformation wieder zu verwenden. Es ist sicherlich leicht zu lösen, und es hat keine quadrierten Terme, so dass Linien in den Richtungen der u,v,w Achsen zu geraden Linien in x,y,z zuordnen. Das bedeutet, dass Ihre Würfelkanten und -flächen sowie die Ecken garantiert übereinstimmen. Mir fehlen jedoch die Berechnungen, um dies zu beweisen, und ich konnte auch keine googlefähigen Informationen finden. Mein Wissen kommt aus einer fernen Erinnerung an Lehrbücher über Finite-Elemente-Methoden, wo diese Art von Transformationen üblich sind.Wenn Sie weitere Informationen benötigen, schlage ich vor, dass Sie dort nachsehen.

+0

Fantastisch. Es hat zwei Stunden gedauert, um diese großartige Lösung in R zu rekonstruieren - aber jetzt funktioniert es. Danke vielmals! Morgen werde ich die resultierende R-Funktion aufräumen und hier posten. – nevrome

1

Dank Rechnungen Erklärung und Beispiele konnte ich mit der folgenden Lösung in R kommen:

# 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" 
) 

Edit:

Diese Funktion jetzt mit RCPP in meinem umgesetzt wird R-Paket recexcavAAR.

+0

Froh, es hat funktioniert :) – Bill

Verwandte Themen