Herhangi bir gerçekten genel amaçlı etkili yöntem, şekillerin temsilini standart hale getirecek, böylece iç gösterimdeki dönme, çeviri, yansıma veya önemsiz değişiklikler üzerine değişmeyeceklerdir.
Bunu yapmanın bir yolu, bağlı her şekli bir uçtan başlayarak alternatif bir kenar uzunlukları ve (işaretli) açı dizisi olarak listelemektir. (Şeklin sıfır uzunluklu kenarları veya düz açıları olmaması anlamında "temiz" olması gerekir.) Bu değişmezi yansıma altında yapmak için, ilk sıfır olmayan negatif ise tüm açıları ortadan kaldırın.
( N köşelerin herhangi bir bağlı çoklu çizgisi n- 2 açı ile ayrılmış n- 1 kenara sahip olacağından, aşağıdaki kodda biri kenar uzunlukları için diğeri kenar uzunlukları için olmak üzere iki diziden oluşan bir veri yapısının kullanılmasını uygun buldum . açıları, bu tür bir veri yapısı içinde sıfır uzunluklu dizi işlemek için önemlidir, böylece. bir doğru parçası, hiçbir açıları olacaktır.)R
$lengths
$angles
Bu tür temsiller sözlükbilimsel olarak sipariş edilebilir. Standardizasyon işlemi sırasında biriken kayan nokta hataları için bir miktar izin verilmelidir. Zarif bir prosedür bu hataları orijinal koordinatların bir fonksiyonu olarak tahmin edecektir. Aşağıdaki çözümde, göreli olarak çok küçük bir miktarda farklılık gösterdiklerinde iki uzunluğun eşit olduğu düşünülen daha basit bir yöntem kullanılmaktadır . Açılar mutlak olarak sadece çok az miktarda farklılık gösterebilir.
Onları altta yatan yönelimin tersine çevrilmesi altında değişmez kılmak için, çoklu çizginin ters çevrimi ile sözlükbilimsel olarak en erken temsili seçin.
Çok parçalı polietilenleri işlemek için bileşenlerini sözlükbilimsel düzende düzenleyin.
Öklid dönüşümleri altındaki denklik sınıflarını bulmak için ,
Şekillerin standartlaştırılmış temsillerini oluşturun.
Standartlaştırılmış gösterimlerin sözlükbilimsel bir türünü gerçekleştirin.
Eşit temsillerin dizilerini tanımlamak için sıralı sıradan bir geçiş yapın.
Hesaplama süresi O (n * log (n) * N) ile orantılıdır; burada n , özellik sayısıdır ve N , herhangi bir özellikteki en fazla köşe noktasıdır. Bu etkilidir.
Muhtemelen, çok hatlı uzunluk, merkez ve o merkezle ilgili anlar gibi kolayca hesaplanan değişmez geometrik özelliklere dayanan bir ön gruplamanın tüm süreci kolaylaştırmak için uygulanabileceğini belirtmek gerekir. Kişinin sadece bu tür her bir ön grupta uyumlu özelliklerin alt gruplarını bulması gerekir. Burada verilen tam yönteme, aksi takdirde bu kadar basit benzerlerin hala onları ayırt etmeyecek kadar benzer olacak şekiller için gerekli olacaktır. Raster verilerinden oluşturulan basit özellikler, örneğin bu özelliklere sahip olabilir. Bununla birlikte, burada verilen çözüm zaten çok verimli olduğu için, eğer onu uygulama çabalarına gidecek olursa, kendi başına iyi çalışabilir.
Misal
Soldaki şekil, rasgele çeviri, döndürme, yansıma ve iç yönelimin (görünür olmayan) tersine çevrilmesi ile elde edilen beş çoklu çizgiyi artı 15 tane daha göstermektedir. Sağ figür onları Öklid eşdeğerlik sınıflarına göre renklendirir: ortak bir rengin tüm figürleri uyumludur; farklı renkler uyumlu değildir.
R
kodu takip eder. Girişler 500 şekle, 500 ekstra (uyumlu) şekle, şekil başına ortalama 100 köşeye güncellendiğinde, bu makinedeki yürütme süresi 3 saniyeydi.
Bu kod eksik: çünkü R
yerel bir sözlükbilimsel sıralama yok ve sıfırdan bir kodlama gibi hissetmedim, ben sadece her standart şeklin ilk koordinatında sıralama gerçekleştirin. Bu, burada oluşturulan rastgele şekiller için iyi olacaktır, ancak üretim çalışmaları için tam bir sözlükbilimsel sıralama uygulanmalıdır. İşlev order.shape
, bu değişiklikten etkilenen tek işlev olacaktır. Girdisi standartlaştırılmış şeklin bir listesidir s
ve çıktısı s
onu sıralayacak dizin dizisidir .
#
# 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)))