चलो पहले कुछ विश्लेषण करते हैं।
बहुभुज के भीतर मान लीजिए P इसकी संभाव्यता घनत्व आनुपातिक कार्य है p(x,y). फिर आनुपातिकता का निरंतर अभिन्न का विलोम है p बहुभुज पर,
μ0,0(P)=∬Pp(x,y)dxdy.
केन्द्रक बहुभुज की औसत निर्देशांक, उनके पहले क्षणों रूप में गणना की है। पहले वाला है
μ1,0(P)=1μ0,0(P)∬Pxp(x,y)dxdy.
जड़त्वीय टेन्सर की मैट्रिक्स जो है,: बहुभुज का अनुवाद मूल में अपने केन्द्रक डाल करने के बाद की गणना की दूसरी क्षणों में से सममित सरणी के रूप में प्रतिनिधित्व किया जा सकता है केंद्रीय दूसरा क्षणों
μ′k,l(P)=1μ0,0(P)∬P(x−μ1,0(P))k(y−μ0,1(P))lp(x,y)dxdy
कहाँ पे (k,l) से रेंज (2,0) सेवा (1,1) सेवा (0,2). दसियों ही - उर्फ कोवरियन मैट्रिक्स - है
I(P)=(μ′2,0(P)μ′1,1(P)μ′1,1(P)μ′0,2(P)).
का एक पी.सी.ए. I(P)की प्रमुख कुल्हाड़ियों की पैदावार करता हैP: ये यूनिट आईजेनवेक्टर हैं, जिन्हें उनके आईजेन्यूल्स द्वारा स्केल किया गया है।
अगला, चलो गणना करने के लिए कैसे काम करते हैं। क्योंकि बहुभुज को अपनी उन्मुख सीमा का वर्णन करने वाले अनुक्रम के रूप में प्रस्तुत किया जाता है∂P, आह्वान करना स्वाभाविक है
ग्रीन की प्रमेय: ∬Pdω=∮∂Pω
कहाँ पे ω=M(x,y)dx+N(x,y)dy के एक पड़ोस में परिभाषित एक रूप है P तथा dω=(∂∂xN(x,y)−∂∂yM(x,y))dxdy.
उदाहरण के लिए, साथ dω=xkyldxdyऔर निरंतर ( यानी , वर्दी) घनत्वp, हम (निरीक्षण द्वारा) कई समाधानों में से एक का चयन कर सकते हैं, जैसे कि ω(x,y)=−1l+1xkyl+1dx.
इसका मतलब यह है कि समोच्च अभिन्न अंग के अनुक्रम द्वारा निर्धारित लाइन खंडों का अनुसरण करता है। शीर्ष से किसी भी लाइन खंडu शीर्ष करने के लिए v एक वास्तविक चर द्वारा पैरामीटर किया जा सकता है t फार्म में
t→u+tw
where w∝v−u is the unit normal direction from u to v. The values of t therefore range from 0 to |v−u|. Under this parameterization x and y are linear functions of t and dx and dy are linear functions of dt. Thus the integrand of the contour integral over each edge becomes a polynomial function of t, which is easily evaluated for small k and l.
Implementing this analysis is as straightforward as coding its components. At the lowest level we will need a function to integrate a polynomial one-form over a line segment. Higher level functions will aggregate these to compute the raw and central moments to obtain the barycenter and inertial tensor, and finally we can operate on that tensor to find the principal axes (which are its scaled eigenvectors). The R
code below performs this work. It makes no pretensions of efficiency: it is intended only to illustrate the practical application of the foregoing analysis. Each function is straightforward and the naming conventions parallel those of the analysis.
Included in the code is a procedure to generate valid closed, simply connected, non-self-intersecting polygons (by randomly deforming points along a circle and including the starting vertex as its final point in order to create a closed loop). Following this are a few statements to plot the polygon, display its vertices, adjoin the barycenter, and plot the principal axes in red (largest) and blue (smallest), creating a polygon-centric positively-oriented coordinate system.
#
# 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")