ลองทำการวิเคราะห์ก่อน
สมมติว่าภายในรูปหลายเหลี่ยม P ความหนาแน่นของความน่าจะเป็นเป็นฟังก์ชันแบบสัดส่วน p ( x , y) . จากนั้นค่าคงที่ของสัดส่วนก็คือค่าผกผันของอินทิกรัลของ พี เหนือรูปหลายเหลี่ยม
μ0 , 0( P) =∬Pp ( x , y) d xd Y.
barycenterของรูปหลายเหลี่ยมเป็นจุดพิกัดเฉลี่ยคำนวณช่วงเวลาแรกของพวกเขา อันแรกก็คือ
μ1,0(P)=1μ0,0(P)∬Pxp(x,y)dxdy.
เมตริกซ์เฉื่อยสามารถแสดงเป็นอาร์เรย์สมมาตรของช่วงเวลาที่สองคำนวณหลังจากแปลรูปหลายเหลี่ยมที่จะนำ barycenter ที่กำเนิด: นั่นคือเมทริกซ์ของช่วงเวลาที่สองกลาง
μ′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)).
PCA ของ I(P)ให้แกนหลักของP: สิ่งเหล่านี้คือค่าลักษณะเฉพาะของหน่วยโดยค่าลักษณะเฉพาะ
ต่อไปเรามาดูวิธีการคำนวณ เนื่องจากรูปหลายเหลี่ยมนั้นแสดงเป็นลำดับของจุดยอดที่อธิบายขอบเขตเชิงของมัน∂P, มันเป็นธรรมชาติที่จะเรียก
ทฤษฎีบทกรีน ∬Pd ω=∮∂Pω
ที่ไหน ω = M( x , y) d x + N( x , y) d y เป็นรูปแบบหนึ่งที่กำหนดไว้ในละแวกของ P และ d ω= (∂∂xยังไม่มีข้อความ( x , y) -∂∂YM( x , y) ) d xd Y.
ตัวอย่างเช่นกับ d ω=xkYล.d x d yและความหนาแน่นคงที่ ( เช่นสม่ำเสมอ)P , เราอาจ (โดยการตรวจสอบ) เลือกหนึ่งในหลาย ๆ วิธีเช่น ω ( x , y) =- 1l + 1xkYl + 1d x
จุดนี้คือสิ่งที่อินทิกรัลของรูปร่างตามส่วนของเส้นตรงที่กำหนดโดยลำดับของจุดยอด ส่วนของเส้นใดก็ได้จากจุดสุดยอดยู เพื่อจุดสุดยอด โวลต์ สามารถแปรค่าโดยตัวแปรจริง เสื้อ ในรูปแบบ
t → u + t w
ที่ไหน w ∝ v - u เป็นทิศทางปกติของหน่วยจาก ยู ถึง v . ค่าของ เสื้อ ดังนั้นช่วงจาก 0 ถึง | v - u | . ภายใต้การปรับพารามิเตอร์นี้ x และ Y ฟังก์ชั่นเชิงเส้นของ เสื้อ และ วันที่ x และ d Y ฟังก์ชั่นเชิงเส้นของ d T ดังนั้นปริพันธ์และอินทิกรัลของเส้นขอบเหนือขอบแต่ละอันจึงกลายเป็นฟังก์ชันพหุนามของเสื้อ, ซึ่งประเมินได้ง่ายสำหรับขนาดเล็ก k และ ล.
การใช้การวิเคราะห์นี้ตรงไปตรงมาเหมือนกับการเขียนโค้ดส่วนประกอบ ในระดับต่ำสุดเราจะต้องมีฟังก์ชั่นเพื่อรวมพหุนามหนึ่งรูปแบบเหนือส่วนของเส้นตรง ฟังก์ชั่นระดับที่สูงขึ้นจะรวมสิ่งเหล่านี้เพื่อคำนวณช่วงเวลาดิบและตอนกลางเพื่อรับ barycenter และเทนเซอร์แรงเฉื่อยและในที่สุดเราก็สามารถทำงานกับเทนเซอร์นั้นเพื่อค้นหาแกนหลัก R
โค้ดด้านล่างนี้ดำเนินงานนี้ ไม่มีข้อ จำกัด เรื่องประสิทธิภาพ: มีวัตถุประสงค์เพื่อแสดงให้เห็นถึงการใช้งานจริงของการวิเคราะห์ที่กล่าวมาข้างต้น แต่ละฟังก์ชั่นนั้นตรงไปตรงมาและอนุสัญญาการตั้งชื่อนั้นขนานกับการวิเคราะห์
รวมอยู่ในรหัสเป็นขั้นตอนในการสร้างปิดที่ถูกต้องเพียงเชื่อมต่อรูปหลายเหลี่ยมที่ไม่ได้ตัดตัวเอง (โดยการสุ่มจุดเปลี่ยนรูปตามวงกลมและรวมจุดสุดยอดเริ่มต้นเป็นจุดสุดท้ายเพื่อสร้างวงปิด) ต่อไปนี้เป็นข้อความสองสามข้อในการพล็อตรูปหลายเหลี่ยมแสดงจุดยอดติด barycenter และพล็อตแกนหลักในสีแดง (ใหญ่ที่สุด) และสีฟ้า (เล็กที่สุด) สร้างระบบพิกัดรูปหลายเหลี่ยมเชิงบวก
#
# 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")