Facciamo prima alcune analisi.
Supponiamo che all'interno del poligono sua densità di probabilità sia la funzione proporzionale Quindi la costante di proporzionalità è l'inverso dell'integrale di sul poligono,Pp(x,y).p
μ0,0(P)=∬Pp(x,y)dxdy.
Il baricentro del poligono è il punto di coordinate medie, calcolato come i loro primi momenti. Il primo è
μ1 , 0( P) = 1μ0 , 0( P)∬PXp ( x , y) d xd y.
Il tensore inerziale può essere rappresentato come la matrice simmetrica dei secondi momenti calcolata dopo aver tradotto il poligono per mettere il suo baricentro all'origine: cioè la matrice dei secondi momenti centrali
μ'k , l( P) = 1μ0 , 0( P)∬P( x - μ1 , 0( P) )K( y- μ0 , 1( P) )lp ( x , y) d xd y
dove vanno da a a Il tensore stesso - alias matrice di covarianza - lo è( k , l )( 2 , 0 )( 1 , 1 )( 0 , 2 ) .
io( P) = ( μ'2 , 0( P)μ'1 , 1( P)μ'1 , 1( P)μ'0 , 2( P)) .
Un PCA di produce gli assi principali di questi sono gli autovettori di unità scalati in base ai loro autovalori.io( P)P :P:
Quindi, scopriamo come eseguire i calcoli. Poiché il poligono è presentato come una sequenza di vertici che ne descrive il confine orientato è naturale invocare∂P,
Teorema di Green: dove è una forma unica definita in un quartiere di e∬Pd ω= ∮∂Pω
ω = M( x , y) d x + N( x , y) d yPd ω= ( ∂∂XN( x , y) - ∂∂yM( x , y) ) d xd y.
Ad esempio, con e densità costante ( cioè uniforme) possiamo (per ispezione) selezionare uno dei tanti soluzioni, comed ω= xKyld x d yp , ω ( x , y ) = - 1p ,ω ( x , y) = - 1l + 1XKyl + 1d x.
Il punto di ciò è che l'integrale del contorno segue i segmenti di linea determinati dalla sequenza dei vertici. Qualsiasi segmento di linea da vertice a vertice può essere parametrizzato da una variabile reale nel modulouvt
t → u + t w
dove è la direzione normale dell'unità da aI valori di pertanto vanno da a Sotto questa parametrizzazione ed sono funzioni lineari di e e sono funzioni lineari di Pertanto l'integrando dell'integrale del contorno su ciascun bordo diventa una funzione polinomiale di che può essere facilmente valutata per piccoli ew∝v−uuv.t0|v−u|.xytdxdydt.t , k l .t,kl .
L'implementazione di questa analisi è semplice come codificare i suoi componenti. Al livello più basso avremo bisogno di una funzione per integrare una forma polinomiale su un segmento di linea. Le funzioni di livello superiore le aggregheranno per calcolare i momenti grezzi e centrali per ottenere il baricentro e il tensore inerziale, e infine potremo operare su quel tensore per trovare gli assi principali (che sono i suoi autovettori scalati). Il R
codice seguente esegue questo lavoro. Non fa pretese di efficienza: intende solo illustrare l'applicazione pratica dell'analisi che precede. Ogni funzione è semplice e le convenzioni di denominazione sono parallele a quelle dell'analisi.
Nel codice è inclusa una procedura per generare poligoni validi chiusi, semplicemente connessi e non autointersecanti (deformando casualmente i punti lungo un cerchio e includendo il vertice iniziale come punto finale per creare un circuito chiuso). Di seguito sono riportate alcune affermazioni per tracciare il poligono, visualizzare i suoi vertici, adiacente al baricentro e tracciare gli assi principali in rosso (il più grande) e blu (il più piccolo), creando un sistema di coordinate orientato positivamente al poligono.
#
# 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")