วิธีที่มีประสิทธิภาพวัตถุประสงค์ทั่วไปอย่างแท้จริงใด ๆ จะสร้างมาตรฐานการเป็นตัวแทนของรูปร่างเพื่อที่พวกเขาจะไม่เปลี่ยนแปลงตามการหมุนการแปลการสะท้อนหรือการเปลี่ยนแปลงเล็กน้อยในการเป็นตัวแทนภายใน
วิธีหนึ่งในการทำเช่นนี้คือรายการรูปร่างที่เชื่อมต่อกันเป็นลำดับสลับของความยาวขอบและมุม (เซ็นชื่อ) เริ่มต้นจากปลายด้านหนึ่ง (รูปร่างควรเป็น "สะอาด" ในแง่ของการไม่มีขอบที่มีความยาวเป็นศูนย์หรือมุมตรง) ในการทำให้ค่าคงที่นี้อยู่ภายใต้การสะท้อนให้ลบมุมทั้งหมดหากไม่เป็นศูนย์แรกที่เป็นค่าลบ
(เนื่องจากรูปหลายเหลี่ยมที่เชื่อมต่อกันของnจุดยอดจะมีขอบn -1 คั่นด้วยมุมn -2 ฉันพบว่ามันสะดวกในR
โค้ดด้านล่างเพื่อใช้โครงสร้างข้อมูลประกอบด้วยสองอาร์เรย์หนึ่งสำหรับความยาวขอบ$lengths
และอีกอันสำหรับ angles,. $angles
ส่วนของเส้นจะไม่มีมุมเลยดังนั้นมันสำคัญที่จะต้องจัดการกับอาร์เรย์ที่มีความยาวเป็นศูนย์ในโครงสร้างข้อมูลดังกล่าว)
การเป็นตัวแทนดังกล่าวสามารถสั่งซื้อพจนานุกรม ควรตั้งค่าเผื่อบางอย่างสำหรับข้อผิดพลาดจุดลอยตัวที่สะสมในระหว่างกระบวนการมาตรฐาน ขั้นตอนที่สวยงามจะประเมินข้อผิดพลาดเหล่านั้นเป็นฟังก์ชันของพิกัดดั้งเดิม ในการแก้ปัญหาด้านล่างวิธีการที่ง่ายกว่านั้นถูกใช้ในการที่ความยาวทั้งสองจะถือว่าเท่ากันเมื่อพวกเขาแตกต่างกันในปริมาณที่น้อยมากบนพื้นฐานที่สัมพันธ์กัน มุมอาจแตกต่างกันเพียงเล็กน้อยในแต่ละครั้ง
ในการทำให้ค่าคงที่ภายใต้การพลิกกลับของการวางแนวพื้นฐานให้เลือกการแทนคำที่เก่าที่สุดระหว่าง lexicographically และการกลับรายการ
หากต้องการจัดการ polylines หลายส่วนให้จัดเรียงส่วนประกอบตามลำดับพจนานุกรม
ในการค้นหาคลาสสมมูลภายใต้การแปลงแบบยุคลิดจากนั้น
สร้างการรับรองมาตรฐานของรูปร่าง
ทำการเรียงลำดับพจนานุกรมของการรับรองมาตรฐาน
ส่งผ่านลำดับที่เรียงลำดับเพื่อระบุลำดับของการแทนเท่ากัน
เวลาในการคำนวณเป็นสัดส่วนกับ O (n * log (n) * N) โดยที่nคือจำนวนของคุณสมบัติและNเป็นจำนวนจุดยอดที่ใหญ่ที่สุดในคุณลักษณะใด ๆ สิ่งนี้มีประสิทธิภาพ
อาจเป็นเรื่องที่ควรกล่าวถึงในการส่งผ่านว่าการจัดกลุ่มเบื้องต้นขึ้นอยู่กับคุณสมบัติทางเรขาคณิตที่คำนวณได้ง่ายเช่นความยาวโพลีไลน์, จุดศูนย์กลาง , และช่วงเวลาที่เกี่ยวกับจุดศูนย์กลางนั้น หนึ่งต้องการค้นหากลุ่มย่อยของคุณสมบัติที่สอดคล้องกันภายในแต่ละกลุ่มเบื้องต้นดังกล่าว วิธีเต็มรูปแบบที่ได้รับที่นี่จะมีความจำเป็นสำหรับรูปร่างที่มิฉะนั้นจะคล้ายกันอย่างน่าทึ่งว่าค่าคงที่แบบง่ายเช่นนี้จะยังไม่แยกพวกเขา คุณลักษณะอย่างง่ายที่สร้างจากข้อมูลแรสเตอร์อาจมีลักษณะเช่นนี้ อย่างไรก็ตามเนื่องจากวิธีการแก้ปัญหาที่ให้ไว้ที่นี่มีประสิทธิภาพอยู่แล้วดังนั้นหากใครจะพยายามใช้งานมันอาจจะทำงานได้ดีด้วยตัวเอง
ตัวอย่าง
รูปมือซ้ายแสดงห้า polylines บวกอีก 15 ที่ได้จากการแปลแบบสุ่มการหมุนการสะท้อนและการพลิกกลับของการวางแนวภายใน (ซึ่งมองไม่เห็น) มือขวาร่างสีตามชนชั้นสมดุลแบบยุคลิดของพวกเขา: ตัวเลขทั้งหมดของสีทั่วไปเป็นสมภาค; สีที่ต่างกันจะไม่สอดคล้องกัน
R
รหัสดังต่อไปนี้ เมื่ออินพุตถูกอัพเดตเป็น 500 รูปร่าง, 500 พิเศษ (สอดคล้องกัน) รูปร่างโดยมีค่าเฉลี่ย 100 จุดต่อรูปร่าง, เวลาดำเนินการของเครื่องนี้คือ 3 วินาที
รหัสนี้ไม่สมบูรณ์:เนื่องจากR
ไม่มีการเรียงลำดับพจนานุกรมดั้งเดิมและฉันไม่รู้สึกเหมือนการเขียนรหัสตั้งแต่เริ่มต้นฉันจึงทำการเรียงลำดับในพิกัดแรกของแต่ละรูปร่างมาตรฐาน นั่นจะเป็นสิ่งที่ดีสำหรับรูปร่างแบบสุ่มที่สร้างขึ้นที่นี่ แต่สำหรับงานผลิตควรใช้การเรียงลำดับพจนานุกรมแบบเต็ม ฟังก์ชั่นorder.shape
จะเป็นเพียงสิ่งเดียวที่ได้รับผลกระทบจากการเปลี่ยนแปลงนี้ อินพุตของมันคือรายการของรูปร่างที่ได้มาตรฐานs
และเอาต์พุตของมันคือลำดับของดัชนีs
ที่จะเรียงลำดับ
#
# Create random shapes.
#
n.shapes <- 5 # Unique shapes, up to congruence
n.shapes.new <- 15 # Additional congruent shapes to generate
p.mean <- 5 # Expected number of vertices per shape
set.seed(17) # Create a reproducible starting point
shape.random <- function(n) matrix(rnorm(2*n), nrow=2, ncol=n)
shapes <- lapply(2+rpois(n.shapes, p.mean-2), shape.random)
#
# Randomly move them around.
#
move.random <- function(xy) {
a <- runif(1, 0, 2*pi)
reflection <- sign(runif(1, -1, 1))
translation <- runif(2, -8, 8)
m <- matrix(c(cos(a), sin(a), -sin(a), cos(a)), 2, 2) %*%
matrix(c(reflection, 0, 0, 1), 2, 2)
m <- m %*% xy + translation
if (runif(1, -1, 0) < 0) m <- m[ ,dim(m)[2]:1]
return (m)
}
i <- sample(length(shapes), n.shapes.new, replace=TRUE)
shapes <- c(shapes, lapply(i, function(j) move.random(shapes[[j]])))
#
# Plot the shapes.
#
range.shapes <- c(min(sapply(shapes, min)), max(sapply(shapes, max)))
palette(gray.colors(length(shapes)))
par(mfrow=c(1,2))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(shapes), function(i) lines(t(shapes[[i]]), col=i, lwd=2)))
#
# Standardize the shape description.
#
standardize <- function(xy) {
n <- dim(xy)[2]
vectors <- xy[ ,-1, drop=FALSE] - xy[ ,-n, drop=FALSE]
lengths <- sqrt(colSums(vectors^2))
if (which.min(lengths - rev(lengths))*2 < n) {
lengths <- rev(lengths)
vectors <- vectors[, (n-1):1]
}
if (n > 2) {
vectors <- vectors / rbind(lengths, lengths)
perps <- rbind(-vectors[2, ], vectors[1, ])
angles <- sapply(1:(n-2), function(i) {
cosine <- sum(vectors[, i+1] * vectors[, i])
sine <- sum(perps[, i+1] * vectors[, i])
atan2(sine, cosine)
})
i <- min(which(angles != 0))
angles <- sign(angles[i]) * angles
} else angles <- numeric(0)
list(lengths=lengths, angles=angles)
}
shapes.std <- lapply(shapes, standardize)
#
# Sort lexicographically. (Not implemented: see the text.)
#
order.shape <- function(s) {
order(sapply(s, function(s) s$lengths[1]))
}
i <- order.shape(shapes.std)
#
# Group.
#
equal.shape <- function(s.0, s.1) {
same.length <- function(a,b) abs(a-b) <= (a+b) * 1e-8
same.angle <- function(a,b) min(abs(a-b), abs(a-b)-2*pi) < 1e-11
r <- function(u) {
a <- u$angles
if (length(a) > 0) {
a <- rev(u$angles)
i <- min(which(a != 0))
a <- sign(a[i]) * a
}
list(lengths=rev(u$lengths), angles=a)
}
e <- function(u, v) {
if (length(u$lengths) != length(v$lengths)) return (FALSE)
all(mapply(same.length, u$lengths, v$lengths)) &&
all(mapply(same.angle, u$angles, v$angles))
}
e(s.0, s.1) || e(r(s.0), s.1)
}
g <- rep(1, length(shapes.std))
for (j in 2:length(i)) {
i.0 <- i[j-1]
i.1 <- i[j]
if (equal.shape(shapes.std[[i.0]], shapes.std[[i.1]]))
g[j] <- g[j-1] else g[j] <- g[j-1]+1
}
palette(rainbow(max(g)))
plot(range.shapes, range.shapes, type="n",asp=1, bty="n", xlab="", ylab="")
invisible(lapply(1:length(i), function(j) lines(t(shapes[[i[j]]]), col=g[j], lwd=2)))