- ここ数日(数週間?)C++で書かれていて、MATLABにはすぐ連結する(らしい)疎行列ライブラリSuiteSparseを用いて離散微分幾何的アプローチの曲面変形について、調べてきた
- RにもSuiteSparse準拠の疎行列用パッケージMatrixがあるので、それに連結してみようといろいろやってきた
- それなりに(遅いけれど)動く模様なので、まずは、図(黒い正球を曲率濃淡ランダム二次元関数に基づいて変形した赤い閉曲面)のようなものが描けますよ、というソース
- ごちゃごちゃしているので、このソースをRmd化しておくことにする(けれど、それは、ちょっと後)
my.readOBJ <-
function (con, ...)
{
lines <- readLines(con)
instrs <- sub(" .*", "", lines)
vertices <- read.table(textConnection(lines[instrs == "v"]),
col.names = c("instr", "x", "y", "z"), colClasses = c(instr = "character",
x = "numeric", y = "numeric", z = "numeric"))
vertices <- with(vertices, rbind(x, y, z))
normals <- c()
normals <- read.table(textConnection(lines[instrs == "vn"]),
col.names = c("instr", "x", "y", "z"), colClasses = c(instr = "character",
x = "numeric", y = "numeric", z = "numeric"))
normals <- with(normals, rbind(x, y, z))
textures <- c()
textures <- read.table(textConnection(lines[instrs == "vt"]),
col.names = c("instr", "x", "y"), colClasses = c(instr = "character",
x = "numeric", y = "numeric"))
textures <- with(textures, rbind(x, y))
tfaces <- grepl("^f\\W+\\w+\\W+\\w+\\W+\\w+$", lines)
triangles <- read.table(textConnection(lines[instrs == "f"]), col.names = c("instr",
"v1", "v2", "v3"), colClasses = "character")
triangles <- with(triangles, rbind(v1, v2, v3))
triangles1 <- triangles2 <- triangles3 <- matrix(0,3,length(triangles[1,]))
for(i in 1:length(triangles[1,])){
for(j in 1:3){
tmp <- unlist(strsplit(triangles[j,i],"/"))
triangles1[j,i] <- as.numeric(tmp[1])
triangles2[j,i] <- as.numeric(tmp[2])
triangles3[j,i] <- as.numeric(tmp[3])
}
}
ret <- list(vertices=vertices,normals=normals,textures=textures,triangles1=triangles1,triangles2=triangles2,triangles3=triangles3)
return(ret)
}
con <- "sphere_original.obj"
obj.data <- my.readOBJ(con)
m <- tmesh3d(obj.data$vertices,obj.data$triangles1,homogeneous=FALSE)
shade3d(m)
library(onion)
vertices <- obj.data$vertices[1,] * Hi + obj.data$vertices[2,] * Hj + obj.data$vertices[3,] * Hk
uv <- obj.data$textures
faces.v <- obj.data$triangles1
faces.uv <- obj.data$triangles2
my.rho <- function(x,y,vs,Vs,Vs2){
X <- x
Y <- y
if(Y < 0.5){
Y <- y*2
}else{
Y <- 2*(y-0.5)
}
X <- (X-0.5)*2
Y <- (Y-0.5)*2
if(X^2+Y^2>1){
return(0)
}
if(y < 0.5){
Y <- -Y
Z <- sqrt(1-(X^2+Y^2))
}else{
Z <- -sqrt(1-(X^2+Y^2))
}
xyz <- c(X,Y,Z)
tmp <- (t(vs) %*% xyz)
for(i in 1:length(tmp)){
if(tmp[i] > 1) tmp[i] <- 1
if(tmp[i] < -1) tmp[i] <- -1
}
tmp <- acos(tmp)
ret <- sum(Vs*exp(-Vs2*tmp^2))
ret
}
x <- runif(30000)
y <- runif(30000)
np <- 4
vs <- matrix(rnorm(np*3),ncol=3)
vs <- vs/sqrt(apply(vs^2,1,sum))
vs <- t(vs)
Vs <- runif(np)*5
Vs2 <- runif(np)*2
rho <- rep(0,length(x))
for(i in 1:length(rho)){
rho[i] <- my.rho(x[i],y[i],vs,Vs,Vs2)
}
rho[which(rho==0)] <- min(rho[rho!=0])-0.01
rho.st <- (max(rho)-rho)/(max(rho)-min(rho))
plot(x,y,col=gray(rho.st),pch=20,asp=TRUE)
rho <- rep(0,length(faces.uv[1,]))
for(i in 1:length(rho)){
threes <- faces.uv[,i]
tmp <- rep(0,3)
for(j in 1:3){
tmp[j] <- my.rho(obj.data$textures[1,threes[j]],obj.data$textures[2,threes[j]],vs,Vs,Vs2)
}
rho[i] <- mean(tmp)
}
rho <- ((rho-min(rho))/(max(rho)-min(rho)) - 0.5)*2*10
rho.v <- rep(0,length(vertices))
xyz.ori <- t(as.matrix(vertices)[2:4,])
np <- 4
NP <- matrix(rnorm(np*3),ncol=3)
NP <- t(t(NP)/sqrt(apply(NP^2,1,sum)))
peak <- rnorm(np)*50
sds <- runif(np)*20
rr <- sample(1:8,np)
for(i in 1:np){
tmp <- (xyz.ori %*% NP[i,])
tmp <- tmp/max(abs(tmp))
tmp <- acos(tmp)
tmp2 <- peak[i] * exp(-(tmp^2)^rr[i]*sds[i])
rho.v <- rho.v + tmp2
}
tmp.rho <- matrix(rho.v[faces.v],ncol=3)
rho <- apply(tmp.rho,1,mean)
rho <- ((rho-min(rho))/(max(rho)-min(rho)) - 0.5)*2*10
rho.st <- (max(rho.v)-rho.v)/(max(rho.v)-min(rho.v))
plot3d(xyz.ori,col=rgb(rho.st,1-rho.st,1))
library(Matrix)
make.E <- function(vertices,faces.v,rho){
edge1 <- vertices[faces.v[2,]]-vertices[faces.v[1,]]
edge2 <- vertices[faces.v[3,]]-vertices[faces.v[1,]]
tmp <- edge1 * edge2
A <- abs(i(tmp)+j(tmp)+k(tmp))/2
coef.a <- -1/(4*A)
coef.b <- rho/6
coef.c <- A*rho^2/9
E.re <- E.i <- E.j <- E.k <- sparseVector(c(0),i=c(1),length=length(vertices)^2)
e.q <- list()
e.q[[1]] <- vertices[faces.v[2,]]-vertices[faces.v[3,]]
e.q[[2]] <- vertices[faces.v[3,]]-vertices[faces.v[1,]]
e.q[[3]] <- vertices[faces.v[1,]]-vertices[faces.v[2,]]
for(i in 1:3){
for(j in 1:3){
tmp <- coef.a * e.q[[i]] * e.q[[j]]+ coef.b * (e.q[[j]] -e.q[[i]] ) + coef.c
addr <- faces.v[i,] + (length(vertices)*(faces.v[j,]-1))
tmp.v <- t(as.matrix(tmp))
tmp.out <- my.vector.access(tmp.v,addr)
E.re <- E.re + sparseVector(tmp.out[[2]][,1],tmp.out[[1]],length(vertices)^2)
E.i <- E.re + sparseVector(tmp.out[[2]][,2],tmp.out[[1]],length(vertices)^2)
E.j <- E.re + sparseVector(tmp.out[[2]][,3],tmp.out[[1]],length(vertices)^2)
E.k <- E.re + sparseVector(tmp.out[[2]][,4],tmp.out[[1]],length(vertices)^2)
ord <- order(addr)
rle.out <- rle(addr[ord])
num.row <- length(rle.out$values)
num.col <- max(rle.out$lengths)
tmp1 <- rep(1:num.row,rle.out$lengths)
tmp2 <- c()
for(k in 1:num.row){
tmp2 <- c(tmp2,1:rle.out$lengths[k])
}
addr2 <- tmp1 + num.row*(tmp2-1)
tmp.M <- matrix(0,num.row,num.col)
tmp.M[addr2] <- Re(tmp[ord])
tmp.sum <- apply(tmp.M,1,sum)
E.re <- E.re + sparseVector(tmp.sum,rle.out$values,length(vertices)^2)
tmp.M[addr2] <- i(tmp)
tmp.sum <- apply(tmp.M,1,sum)
E.i <- E.i + sparseVector(tmp.sum,rle.out$values,length(vertices)^2)
tmp.M[addr2] <- j(tmp)
tmp.sum <- apply(tmp.M,1,sum)
E.j <- E.j + sparseVector(tmp.sum,rle.out$values,length(vertices)^2)
tmp.M[addr2] <- k(tmp)
tmp.sum <- apply(tmp.M,1,sum)
E.k <- E.k + sparseVector(tmp.sum,rle.out$values,length(vertices)^2)
}
}
return(list(E.re=Matrix(E.re,length(vertices),length(vertices)),E.i=Matrix(E.i,length(vertices),length(vertices)),E.j=Matrix(E.j,length(vertices),length(vertices)),E.k=Matrix(E.k,length(vertices),length(vertices))))
}
my.vector.access <- function(v,a,func=sum,zero=0){
if(is.vector(v)){
v <- matrix(v,ncol=1)
}
ord <- order(a)
rle.out <- rle(a[ord])
num.row <- length(rle.out[[1]])
num.col <- max(rle.out[[1]])
tmp1 <- rep(1:num.row,rle.out[[1]])
tmp2 <- c()
for(i in 1:num.row){
tmp2 <- c(tmp2,1:rle.out[[1]][i])
}
addr <- tmp1 + num.row*(tmp2-1)
ret.v <- matrix(0,num.row,ncol(v))
for(i in 1:ncol(v)){
if(zero==0){
tmp.V <- sparseVector(v[ord,i],i=addr,length=num.row*num.col)
M <- Matrix(tmp.V,num.row,num.col)
}else{
M <- matrix(zero,num.row,num.col)
M[addr] <- v[ord,i]
}
ret.v[,i] <- apply(M,1,func)
}
return(list(A = rle.out[[2]],V = ret.v))
}
v <- 1:10
v <- cbind(1:10,1:10)
a <- banchi <- c(1,2,3,1,2,4,50,1,3,2)
oo <- my.vector.access(v,a)
oo2 <- my.vector.access(v,a,func=prod,zero=1)
make.E <- function(vertices,faces.v,rho){
edge1 <- vertices[faces.v[2,]]-vertices[faces.v[1,]]
edge2 <- vertices[faces.v[3,]]-vertices[faces.v[1,]]
tmp <- edge1 * edge2
A <- abs(i(tmp)+j(tmp)+k(tmp))/2
coef.a <- -1/(4*A)
coef.b <- rho/6
coef.c <- A*rho^2/9
E.re <- E.i <- E.j <- E.k <- sparseVector(c(0),i=c(1),length=length(vertices)^2)
e.q <- list()
e.q[[1]] <- vertices[faces.v[2,]]-vertices[faces.v[3,]]
e.q[[2]] <- vertices[faces.v[3,]]-vertices[faces.v[1,]]
e.q[[3]] <- vertices[faces.v[1,]]-vertices[faces.v[2,]]
for(i in 1:3){
for(j in 1:3){
tmp <- coef.a * e.q[[i]] * e.q[[j]]+ coef.b * (e.q[[j]] -e.q[[i]] ) + coef.c
addr <- faces.v[i,] + (length(vertices)*(faces.v[j,]-1))
tmp.v <- t(as.matrix(tmp))
tmp.out <- my.vector.access(tmp.v,addr)
E.re <- E.re + sparseVector(tmp.out[[2]][,1],tmp.out[[1]],length(vertices)^2)
E.i <- E.re + sparseVector(tmp.out[[2]][,2],tmp.out[[1]],length(vertices)^2)
E.j <- E.re + sparseVector(tmp.out[[2]][,3],tmp.out[[1]],length(vertices)^2)
E.k <- E.re + sparseVector(tmp.out[[2]][,4],tmp.out[[1]],length(vertices)^2)
}
}
return(list(E.re=Matrix(E.re,length(vertices),length(vertices)),E.i=Matrix(E.i,length(vertices),length(vertices)),E.j=Matrix(E.j,length(vertices),length(vertices)),E.k=Matrix(E.k,length(vertices),length(vertices))))
}
make.E.v <- function(vertices,faces.v,rho){
edge1 <- vertices[faces.v[2,]]-vertices[faces.v[1,]]
edge2 <- vertices[faces.v[3,]]-vertices[faces.v[1,]]
tmp <- edge1 * edge2
A <- abs(i(tmp)+j(tmp)+k(tmp))/2
coef.a <- -1/(4*A)
coef.b <- rho/6
coef.c <- A*rho^2/9
E.re <- E.i <- E.j <- E.k <- sparseVector(c(0),i=c(1),length=length(vertices)^2)
e.q <- list()
e.q[[1]] <- vertices[faces.v[2,]]-vertices[faces.v[3,]]
e.q[[2]] <- vertices[faces.v[3,]]-vertices[faces.v[1,]]
e.q[[3]] <- vertices[faces.v[1,]]-vertices[faces.v[2,]]
for(i in 1:3){
for(j in 1:3){
tmp <- coef.a * e.q[[i]] * e.q[[j]]+ coef.b * (e.q[[j]] -e.q[[i]] ) + coef.c
addr <- faces.v[i,] + (length(vertices)*(faces.v[j,]-1))
tmp.v <- t(as.matrix(tmp))
tmp.out <- my.vector.access(tmp.v,addr)
E.re <- E.re + sparseVector(tmp.out[[2]][,1],tmp.out[[1]],length(vertices)^2)
E.i <- E.re + sparseVector(tmp.out[[2]][,2],tmp.out[[1]],length(vertices)^2)
E.j <- E.re + sparseVector(tmp.out[[2]][,3],tmp.out[[1]],length(vertices)^2)
E.k <- E.re + sparseVector(tmp.out[[2]][,4],tmp.out[[1]],length(vertices)^2)
}
}
return(list(E.re=E.re,E.i=E.i,E.j=E.j,E.k=E.k))
}
my.qMtorM <- function(Es){
n <- sqrt(length(Es[[1]]))
N <- (n*4)^2
init.id <- c(1:4,(1:4)+n*4,(1:4)+n*4*2,(1:4)+n*4*3)
spacing.id <- c(outer((0:(n-1)*4),n*4*4*(0:(n-1)),"+"))
ret <- sparseVector(c(0),i=c(1),N)
a <- c(1,2,3,4,2,1,4,3,3,4,1,2,4,3,2,1)
b <- c(1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,1,-1,1)
for(j in 1:length(a)){
tmp.v <- sparseVector(b[j] * Es[[a[j]]]@x,i=init.id[j]+spacing.id[Es[[a[j]]]@i],length=N)
ret <- ret + tmp.v
}
Matrix(ret,n*4,n*4)
}
n <- 100
p <- 10
s <- sample(1:n,p)
h <- rquat(p)
tmp.Es.v <- list(sparseVector(Re(h),s,n),sparseVector(i(h),s,n),sparseVector(j(h),s,n),sparseVector(k(h),s,n))
N <- 10
n <- N^2
p <- 80
s <- sample(1:n,p)
h <- rquat(p)
tmp.Es.v <- list(sparseVector(Re(h),s,n),sparseVector(i(h),s,n),sparseVector(j(h),s,n),sparseVector(k(h),s,n))
tmp.Es.real <- my.qMtorM(tmp.Es.v)
image(tmp.Es.real)
my.qVtorV <- function(v){
c(as.matrix(v))
}
tmp.v <- rquat(10)
tmp.v
my.qVtorV(tmp.v)
my.linear.solver <- function(Es,b){
b.re <- my.qVtorV(b)
E.re <- my.qMtorM(Es)
solve(E.re,b.re)
}
N <- 10
n <- N^2
p <- 80
s <- sample(1:n,p)
h <- rquat(p)
tmp.Es.v <- list(sparseVector(Re(h),s,n),sparseVector(i(h),s,n),sparseVector(j(h),s,n),sparseVector(k(h),s,n))
tmp.v <- rquat(10)
my.linear.solver(tmp.Es.v,tmp.v)
b <- rep(1+1*Hi+1*Hj+1*Hk,nrow(Es[[1]]))
tmp.out <- my.linear.solver(Es.v,b)
plot(tmp.out)
my.inv.pow <- function(A,n.iter=3,b=rep(1,ncol(A)),log=FALSE){
x <- b
if(log){
x.log <- matrix(0,n.iter+1,ncol(A))
x.log[1,] <- x
}
A. <- solve(A)
for(i in 1:n.iter){
x <- A. %*% x
x <- x/sqrt(sum(x^2))
if(log){
x.log[i+1,] <- x
}
}
if(log){
return(list(x=x,x.log=x.log))
}else{
return(list(x=x,x.log=matrix(0,0,ncol(A))))
}
}
my.inv.pow.2 <- function(A,n.iter=3,b=rep(1,ncol(A)),log=FALSE){
x <- b
if(log){
x.log <- matrix(0,n.iter+1,ncol(A))
x.log[1,] <- x
}
for(i in 1:n.iter){
x2 <- solve(A,x)
x <- x2/sqrt(sum(x2^2))
if(log){
x.log[i+1,] <- x
}
}
if(log){
return(list(x=x,x.log=x.log))
}else{
return(list(x=x,x.log=matrix(0,0,ncol(A))))
}
}
tmp.Es.v <- list()
for(i in 1:4){
tmp.Es.v[[i]] <- sparseVector(rnorm(16),i=1:16,length=16)
}
N <- 20
X <- matrix(rnorm(N^2),N,N)
b <- rnorm(N)
tmp.outs <- my.inv.pow(X,n.iter=100,b=b,log=TRUE)
tmp.outs.2 <- my.inv.pow(X,n.iter=100,b=b,log=TRUE)
matplot(tmp.outs[[2]],type="l")
Es.v <- make.E.v(vertices,faces.v,rho)
E.re <- my.qMtorM(Es.v)
lambda <- my.inv.pow.2(E.re,n.iter=3)[[1]]
plot(lambda)
my.make.L <- function(vertices,faces.v){
n.v <- length(vertices)
L <- sparseVector(c(0),i=c(1),length=n.v^2)
for(i in 1:3){
v.ord <- ((1:3)+i+1) %% 3 + 1
k1 <- faces.v[v.ord[1],]
k2 <- faces.v[v.ord[2],]
k3 <- faces.v[v.ord[3],]
v1 <- vertices[k1]
v2 <- vertices[k2]
v3 <- vertices[k3]
u1 <- v2-v1
u2 <- v3-v1
u12 <- u1 * u2
cotAlpha <- (-Re(u12))/Mod(Im(u12))
addrk2k2 <- k2 + (k2-1)*n.v
addrk3k3 <- k3 + (k3-1)*n.v
addrk2k3 <- k2 + (k3-1)*n.v
addrk3k2 <- k3 + (k2-1)*n.v
addr <- c(addrk2k2,addrk3k3,addrk2k3,addrk3k2)
val <- c(cotAlpha,cotAlpha,-cotAlpha,-cotAlpha)/2
tmp.out <- my.vector.access(val,addr)
L <- L + sparseVector(tmp.out[[2]][,1],tmp.out[[1]],n.v^2)
}
L
}
L <- my.make.L(vertices,faces.v)
my.make.omega <- function(vertices,faces.v,lambda){
n.v <- length(vertices)
omega <- rep(0*Hi,n.v)
for(i in 1:3){
v.ord <- ((1:3)+i+1) %% 3 + 1
k1 <- faces.v[v.ord[1],]
k23 <- rbind(faces.v[v.ord[2],],faces.v[v.ord[3],])
k23 <- apply(k23,2,sort)
k2 <- k23[2,]
k3 <- k23[1,]
v1 <- vertices[k1]
v2 <- vertices[k2]
v3 <- vertices[k3]
edge <- v3-v2
lambda.mat <- matrix(lambda,nrow=4)
lambda.q <- as.quaternion(lambda.mat)
lambda.mat.2 <- lambda.mat
lambda.mat.2[2:4,] <- -lambda.mat.2[2:4,]
lambda.q. <- as.quaternion(lambda.mat.2)
lambda1 <- lambda.q[k2]
lambda1. <- lambda.q.[k2]
lambda2 <- lambda.q[k3]
lambda2. <- lambda.q.[k3]
val <- 1/3 * lambda1. * edge * lambda1 + 1/6 * lambda1. * edge * lambda2 + 1/6 * lambda2. * edge * lambda1 + 1/3 * lambda2. * edge * lambda2
u1 <- v2-v1
u2 <- v3-v1
u12 <- u1 * u2
cotAlpha <- (-Re(u12))/Mod(Im(u12))
Val <- cotAlpha * val /2
Val.m <- t(as.matrix(Val))
tmp.out2 <- my.vector.access(-Val.m,k2)
tmp.out3 <- my.vector.access(Val.m,k3)
omega[tmp.out2[[1]]] <- omega[tmp.out2[[1]]] + as.quaternion(t(tmp.out2[[2]]))
omega[tmp.out3[[1]]] <- omega[tmp.out3[[1]]] + as.quaternion(t(tmp.out3[[2]]))
}
omega.re <- as.matrix(omega)
omega.re <- omega.re-apply(omega.re,1,mean)
c(omega.re)
}
lambda.q <- as.quaternion(matrix(lambda,nrow=4))
omega <- my.make.omega(vertices,faces.v,lambda)
L.q <- list()
L.q[[1]] <- L
for(i in 2:4){
L.q[[i]] <- L*0
}
L.re <- my.qMtorM(L.q)
new.vertices <- solve(L.re,omega)
new.vertices <- as.quaternion(matrix(new.vertices,nrow=4))
newVertices <- matrix(new.vertices,nrow=4)[2:4,]
xyz.ori <- t(as.matrix(vertices)[2:4,])
xyz.new <- t(as.matrix(new.vertices)[2:4,])
mean.ori <- apply(xyz.ori,2,mean)
xyz.ori. <- t(t(xyz.ori)-mean.ori)
mean.new <- apply(xyz.new,2,mean)
xyz.new. <- t(t(xyz.new)-mean.new)
max.ori. <- max(abs(xyz.ori.))
xyz.ori.st <- xyz.ori./max.ori.
max.new. <- max(abs(xyz.new.))
xyz.new.st <- xyz.new./max.new.
plot3d(rbind(xyz.ori.st,xyz.new.st),col=rep(1:2,each=length(xyz.ori[,1])))
plot(c(xyz.ori),c(xyz.new))
library(rgl)
plot3d(t(as.matrix(vertices)[2:4,]))
open3d()
plot3d(t(as.matrix(new.vertices)[2:4,]))