Mari kita lakukan analisis terlebih dahulu.
Misalkan dalam poligon kepadatan probabilitasnya adalah fungsi proporsional Maka konstanta proporsionalitas adalah kebalikan dari integral atas poligon,Pp(x,y).p
μ0,0(P)=∬Pp(x,y)dxdy.
The barycenter dari poligon adalah titik koordinat rata-rata, dihitung sebagai momen pertama mereka. Yang pertama adalah
μ1,0(P)=1μ0,0(P)∬Pxp(x,y)dxdy.
The tensor inersia dapat direpresentasikan sebagai array simetris saat kedua dihitung setelah menerjemahkan poligon untuk menempatkan barycenter pada titik asal: yaitu, matriks momen kedua pusat
μ′k,l(P)=1μ0,0(P)∬P(x−μ1,0(P))k(y−μ0,1(P))lp(x,y)dxdy
di mana berkisar dari hingga hingga Tensor itu sendiri - alias matriks kovarians - adalah(k,l)(2,0)(1,1)(0,2).
I(P)=(μ′2,0(P)μ′1,1(P)μ′1,1(P)μ′0,2(P)).
PCA menghasilkan sumbu utama dari ini adalah vektor satuan eigen yang diukur oleh nilai eigennya.I(P)P :P:
Selanjutnya, mari kita cari tahu cara melakukan perhitungan. Karena poligon disajikan sebagai urutan simpul yang menggambarkan batas berorientasi adalah wajar untuk memanggil∂P,
Teorema Green: mana adalah satu-bentuk yang didefinisikan di lingkungan dan∬Pdω=∮∂Pω
ω=M(x,y)dx+N(x,y)dyPdω=(∂∂xN(x,y)−∂∂yM(x,y))dxdy.
Misalnya, dengan dan kepadatan konstan ( mis. , Seragam) kita dapat (dengan inspeksi) memilih salah satu dari banyak solusi, sepertidω=xkyldxdyp,ω(x,y)=−1l+1xkyl+1dx.
Intinya adalah bahwa integral kontur mengikuti segmen garis yang ditentukan oleh urutan simpul. Segmen baris apa pun dari vertex ke vertex dapat diparameterisasi dengan variabel nyata dalam formuliruvt
t→u+tw
di mana adalah arah normal satuan dari keNilai karena itu berkisar dari hingga Di bawah parameterisasi ini dan adalah fungsi linear dari dan dan adalah fungsi linear dari Dengan demikian integran dari integral kontur atas setiap tepi menjadi fungsi polinom dari yang mudah dievaluasi untuk kecil danw∝v−uuv.t0|v−u|.xytdxdydt.t,kl.
Menerapkan analisis ini sama mudahnya dengan mengkodekan komponen-komponennya. Pada level terendah kita akan memerlukan fungsi untuk mengintegrasikan satu-bentuk polinomial pada segmen garis. Fungsi tingkat yang lebih tinggi akan mengumpulkan ini untuk menghitung momen mentah dan pusat untuk mendapatkan barycenter dan tensor inersia, dan akhirnya kita dapat beroperasi pada tensor tersebut untuk menemukan sumbu utama (yang merupakan vektor eigen yang diskalakan). The R
kode di bawah melakukan pekerjaan ini. Itu tidak membuat pretensi efisiensi: ini dimaksudkan hanya untuk menggambarkan penerapan praktis dari analisis sebelumnya. Setiap fungsi mudah dan konvensi penamaan sejajar dengan analisis.
Termasuk dalam kode adalah prosedur untuk menghasilkan poligon tertutup, hanya terhubung, non-self-berpotongan yang valid (dengan mendeformasi secara acak titik-titik di sepanjang lingkaran dan termasuk titik awal sebagai titik terakhir untuk membuat loop tertutup). Berikut ini adalah beberapa pernyataan untuk memplot poligon, menampilkan simpulnya, berdampingan dengan barycenter, dan memplot sumbu utama dalam warna merah (terbesar) dan biru (terkecil), menciptakan sistem koordinat poligon-sentris berorientasi positif.
#
# Integrate a monomial one-form x^k*y^l*dx along the line segment given as an
# origin, unit direction vector, and distance.
#
lintegrate <- function(k, l, origin, normal, distance) {
# Binomial theorem expansion of (u + tw)^k
expand <- function(k, u, w) {
i <- seq_len(k+1)-1
u^i * w^rev(i) * choose(k,i)
}
# Construction of the product of two polynomials times a constant.
omega <- normal[1] * convolve(rev(expand(k, origin[1], normal[1])),
expand(l, origin[2], normal[2]),
type="open")
# Integrate the resulting polynomial from 0 to `distance`.
sum(omega * distance^seq_along(omega) / seq_along(omega))
}
#
# Integrate monomials along a piecewise linear path given as a sequence of
# (x,y) vertices.
#
cintegrate <- function(xy, k, l) {
n <- dim(xy)[1]-1 # Number of edges
sum(sapply(1:n, function(i) {
dv <- xy[i+1,] - xy[i,] # The direction vector
lambda <- sum(dv * dv)
if (isTRUE(all.equal(lambda, 0.0))) {
0.0
} else {
lambda <- sqrt(lambda) # Length of the direction vector
-lintegrate(k, l+1, xy[i,], dv/lambda, lambda) / (l+1)
}
}))
}
#
# Compute moments of inertia.
#
inertia <- function(xy) {
mass <- cintegrate(xy, 0, 0)
barycenter = c(cintegrate(xy, 1, 0), cintegrate(xy, 0, 1)) / mass
uv <- t(t(xy) - barycenter) # Recenter the polygon to obtain central moments
i <- matrix(0.0, 2, 2)
i[1,1] <- cintegrate(uv, 2, 0)
i[1,2] <- i[2,1] <- cintegrate(uv, 1, 1)
i[2,2] <- cintegrate(uv, 0, 2)
list(Mass=mass,
Barycenter=barycenter,
Inertia=i / mass)
}
#
# Find principal axes of an inertial tensor.
#
principal.axes <- function(i.xy) {
obj <- eigen(i.xy)
t(t(obj$vectors) * obj$values)
}
#
# Construct a polygon.
#
circle <- t(sapply(seq(0, 2*pi, length.out=11), function(a) c(cos(a), sin(a))))
set.seed(17)
radii <- (1 + rgamma(dim(circle)[1]-1, 3, 3))
radii <- c(radii, radii[1]) # Closes the loop
xy <- circle * radii
#
# Compute principal axes.
#
i.xy <- inertia(xy)
axes <- principal.axes(i.xy$Inertia)
sign <- sign(det(axes))
#
# Plot barycenter and principal axes.
#
plot(xy, bty="n", xaxt="n", yaxt="n", asp=1, xlab="x", ylab="y",
main="A random polygon\nand its principal axes", cex.main=0.75)
polygon(xy, col="#e0e0e080")
arrows(rep(i.xy$Barycenter[1], 2),
rep(i.xy$Barycenter[2], 2),
-axes[1,] + i.xy$Barycenter[1], # The -signs make the first axis ..
-axes[2,]*sign + i.xy$Barycenter[2],# .. point to the right or down.
length=0.1, angle=15, col=c("#e02020", "#4040c0"), lwd=2)
points(matrix(i.xy$Barycenter, 1, 2), pch=21, bg="#404040")