Обчислення максимальної відстані в межах багатокутника у напрямку x (схід-захід) у PostGIS?


13

Мене цікавить максимальна ширина багатокутника, наприклад озера, у напрямку схід-захід. Обмежувальні коробки допоможуть лише у простих багатокутниках, але не у складних увігнутих багатокутників.


3
Я не знайомий з функціями постгіс. Однак може бути інструмент для обмеження коробки. Ширина обмежувальної коробки була б максимальною відстані в напрямку EW.
Фестер

4
@Fetzter це невірно: контрприклад навіть для простого складного багатокутника - це тонкий ромб, що простягається від SW до NE. Його максимальна ширина схід-захід може бути довільно невеликою часткою ширини його обмежувальної коробки.
whuber

1
Я створив утиліту для цього завдання на основі цієї та цих пропозицій. Він здатний обчислити максимальну або мінімальну ширину багатокутника. В даний час він працює з shp-файлами, але ви можете переписати його на роботу з PostGIS або просто почекати деякий час, поки він не перетвориться на плагін QGIS, який також буде працювати з PostGIS. Детальний опис та посилання для завантаження тут .
SS_Rebelious

Відповіді:


16

Це, ймовірно, вимагає певного сценарію в будь-якій GIS-платформі.

Найефективніший метод (асимптотично) - це вертикальна лінія зчитування: він вимагає сортування ребер за їх мінімальними y-координатами, а потім обробку країв знизу (мінімум y) до верху (максимум y), для O (e * log ( д)) алгоритм, коли задіяні e краї.

Процедура, хоча і проста, напрочуд складна у всіх випадках. Полігони можуть бути бридкими: вони можуть мати звисання, ковзання, отвори, бути від’єднаними, мати дублювані вершини, прогони вершин за прямими лініями та мати нерозв’язані межі між двома сусідніми компонентами. Ось приклад, який демонструє багато цих характеристик (і більше):

Багатокутник

Ми будемо спеціально шукати горизонтальний відрізок максимальної довжини, що повністю лежить в межах закриття полігону. Наприклад, це виключає зависання між x = 20 і x = 40, що виходить з отвору між x = 10 і x = 25. Тоді прямо можна показати, що принаймні один з горизонтальних відрізків максимальної довжини перетинає щонайменше одну вершину. (Якщо є рішення не перетинаються вершин , вони будуть лежати всередині деякого паралелограма , обмеженого зверху і знизу рішеннями , які роблять перетинаються щонайменше , одну вершини. Це дає нам засіб , щоб знайти всі рішення.)

Відповідно, розміщення рядків повинно починатися з найнижчих вершин, а потім рухатися вгору (тобто у бік більш високих значень y), щоб зупинитися на кожній вершині. На кожній зупинці ми знаходимо будь-які нові краї, що виходять вгору від цієї висоти; усуньте будь-які краї, що закінчуються знизу на цьому висоті (це одна з ключових ідей: це спрощує алгоритм і виключає половину потенційної обробки); і ретельно обробляйте будь-які краї, що лежать повністю на постійній висоті (горизонтальні краї).

Наприклад, розглянемо стан, коли досягнуто рівня y = 10. Зліва направо ми знаходимо такі краї:

      x.min x.max y.min y.max
 [1,]    10     0     0    30
 [2,]    10    24    10    20
 [3,]    20    24    10    20
 [4,]    20    40    10    10
 [5,]    40    20    10    10
 [6,]    60     0     5    30
 [7,]    60    60     5    30
 [8,]    60    70     5    20
 [9,]    60    70     5    15
[10,]    90   100    10    40

У цій таблиці (x.min, y.min) - координати нижньої кінцевої точки краю і (x.max, y.max) - координати його верхньої кінцевої точки. На цьому рівні (у = 10) перший край перехоплюється всередині його внутрішнього, другий перехоплюється внизу тощо. Деякі краї, що закінчуються на цьому рівні, наприклад (від 10,0) до (10,10), не включаються до списку.

Щоб визначити, де розташовані внутрішні точки та зовнішні, подумайте, починаючи з крайньої лівої сторони, - звичайно, поза полігоном - і рухаючись горизонтально праворуч. Кожен раз, коли ми перетинаємо край, який не є горизонтальним , ми по черзі переходимо від зовнішнього до внутрішнього та заднього. (Це ще одна ключова ідея.) Однак усі точки в будь-якому горизонтальному краї визначаються як всередині багатокутника, незалежно від того. (Замикання багатокутника завжди включає його краї.)

Продовжуючи приклад, ось відсортований список x-координат, де не горизонтальні ребра починаються з або перетинають рядок y = 10:

x.array    6.7 10 20 48 60 63.3 65 90
interior     1  0  1  0  1    0  1  0

(Зверніть увагу, що x = 40 немає в цьому списку.) Значення interiorмасиву позначають ліві кінцеві точки внутрішніх сегментів: 1 позначає внутрішній інтервал, 0 зовнішній інтервал. Таким чином, перший 1 вказує інтервал від x = 6,7 до x = 10 знаходиться всередині полігону. Наступний 0 вказує, що інтервал від x = 10 до x = 20 знаходиться поза полігоном. І так воно триває: масив ідентифікує чотири окремі проміжки, як всередині багатокутника.

Деякі з цих інтервалів, наприклад, від x = 60 до x = 63.3, не перетинають жодних вершин: швидка перевірка на x-координати всіх вершин з y = 10 усуває такі інтервали.

Під час сканування ми можемо відстежувати довжину цих інтервалів, зберігаючи дані щодо максимально тривалого інтервалу, знайденого дотепер.

Зауважте деякі наслідки такого підходу. Вершина у формі "v" - це походження двох ребер. Тому при його перетині виникають два перемикачі. Ці вимикачі скасовуються. Будь-яке "v" перевернуте навіть не обробляється, оскільки обидва його краю усуваються перед початком сканування зліва направо. В обох випадках така вершина не відмикає горизонтальний відрізок.

Більше двох ребер можуть мати спільну вершину: це показано в (10,0), (60,5), (25, 20), і - хоча важко сказати - у (20,10) та (40 , 10). (Це тому, що висить (20,10) -> (40,10) -> (40,0) -> (40, -50) -> (40, 10) -> (20, 10) .Зверніть увагу, як вершина (40,0) також знаходиться у внутрішній частині іншого краю ... це жахливо.) Цей алгоритм справляється з цими ситуаціями просто чудово.

Внизу проілюстрована складна ситуація: x-координати негоризонтальних сегментів є

30, 50

Це змушує все ліворуч від x = 30 вважати зовнішнім, все між 30 і 50 - інтер'єром, а все після 50 знову - зовнішнім. Вершина при x = 40 ніколи навіть не розглядається в цьому алгоритмі.

Ось як виглядає багатокутник наприкінці сканування. Я показую всі внутрішні інтервали, що містять вершини, темно-сірого кольору, будь-які інтервали максимальної довжини червоним кольором, і забарвлюю вершини відповідно до їх y-координат. Максимальний інтервал - 64 одиниці.

Після сканування

Єдині геометричні обчислення, що беруть участь, - це обчислення, де ребра перетинаються горизонтальними лініями: це проста лінійна інтерполяція. Також необхідні розрахунки, щоб визначити, які внутрішні сегменти містять вершини: це визначення між розмірами , які легко обчислюються з парою нерівностей. Ця простота робить алгоритм надійним і відповідним як для цілих, так і для координатних представлень з плаваючою точкою.

Якщо координати географічні , то горизонтальні лінії дійсно знаходяться на колах широти. Їх довжини не складно обчислити: просто помножте їх евклідові довжини на косинус їх широти (за сферичною моделлю). Тому цей алгоритм добре пристосовується до географічних координат. . крива, цей алгоритм правильно знайде максимальний горизонтальний відрізок.)


Далі йде Rкод, реалізований для виконання обчислень та створення ілюстрацій.

#
# Plotting functions.
#
points.polygon <- function(p, ...) {
  points(p$v, ...)
}
plot.polygon <- function(p, ...) {
  apply(p$e, 1, function(e) lines(matrix(e[c("x.min", "x.max", "y.min", "y.max")], ncol=2), ...))
}
expand <- function(bb, e=1) {
  a <- matrix(c(e, 0, 0, e), ncol=2)
  origin <- apply(bb, 2, mean)
  delta <-  origin %*% a - origin
  t(apply(bb %*% a, 1, function(x) x - delta))
}
#
# Convert polygon to a better data structure.
#
# A polygon class has three attributes:
#   v is an array of vertex coordinates "x" and "y" sorted by increasing y;
#   e is an array of edges from (x.min, y.min) to (x.max, y.max) with y.max >= y.min, sorted by y.min;
#   bb is its rectangular extent (x0,y0), (x1,y1).
#
as.polygon <- function(p) {
  #
  # p is a list of linestrings, each represented as a sequence of 2-vectors 
  # with coordinates in columns "x" and "y". 
  #
  f <- function(p) {
    g <- function(i) {
      v <- p[(i-1):i, ]
      v[order(v[, "y"]), ]
    }
    sapply(2:nrow(p), g)
  }
  vertices <- do.call(rbind, p)
  edges <- t(do.call(cbind, lapply(p, f)))
  colnames(edges) <- c("x.min", "x.max", "y.min", "y.max")
  #
  # Sort by y.min.
  #
  vertices <- vertices[order(vertices[, "y"]), ]
  vertices <- vertices[!duplicated(vertices), ]
  edges <- edges[order(edges[, "y.min"]), ]

  # Maintaining an extent is useful.
  bb <- apply(vertices <- vertices[, c("x","y")], 2, function(z) c(min(z), max(z)))

  # Package the output.
  l <- list(v=vertices, e=edges, bb=bb); class(l) <- "polygon"
  l
}
#
# Compute the maximal horizontal interior segments of a polygon.
#
fetch.x <- function(p) {
  #
  # Update moves the line from the previous level to a new, higher level, changing the
  # state to represent all edges originating or strictly passing through level `y`.
  #
  update <- function(y) {
    if (y > state$level) {
      state$level <<- y
      #
      # Remove edges below the new level from state$current.
      #
      current <- state$current
      current <- current[current[, "y.max"] > y, ]
      #
      # Adjoin edges at this level.
      #
      i <- state$i
      while (i <= nrow(p$e) && p$e[i, "y.min"] <= y) {
        current <- rbind(current, p$e[i, ])
        i <- i+1
      }
      state$i <<- i
      #
      # Sort the current edges by x-coordinate.
      #
      x.coord <- function(e, y) {
        if (e["y.max"] > e["y.min"]) {
          ((y - e["y.min"]) * e["x.max"] + (e["y.max"] - y) * e["x.min"]) / (e["y.max"] - e["y.min"])
        } else {
          min(e["x.min"], e["x.max"])
        }
      }
      if (length(current) > 0) {
        x.array <- apply(current, 1, function(e) x.coord(e, y))
        i.x <- order(x.array)
        current <- current[i.x, ]
        x.array <- x.array[i.x]     
        #
        # Scan and mark each interval as interior or exterior.
        #
        status <- FALSE
        interior <- numeric(length(x.array))
        for (i in 1:length(x.array)) {
          if (current[i, "y.max"] == y) {
            interior[i] <- TRUE
          } else {
            status <- !status
            interior[i] <- status
          }
        }
        #
        # Simplify the data structure by retaining the last value of `interior`
        # within each group of common values of `x.array`.
        #
        interior <- sapply(split(interior, x.array), function(i) rev(i)[1])
        x.array <- sapply(split(x.array, x.array), function(i) i[1])

        print(y)
        print(current)
        print(rbind(x.array, interior))


        markers <- c(1, diff(interior))
        intervals <- x.array[markers != 0]
        #
        # Break into a list structure.
        #
        if (length(intervals) > 1) {
          if (length(intervals) %% 2 == 1) 
            intervals <- intervals[-length(intervals)]
          blocks <- 1:length(intervals) - 1
          blocks <- blocks - (blocks %% 2)
          intervals <- split(intervals, blocks)  
        } else {
          intervals <- list()
        }
      } else {
        intervals <- list()
      }
      #
      # Update the state.
      #
      state$current <<- current
    }
    list(y=y, x=intervals)
  } # Update()

  process <- function(intervals, x, y) {
    # intervals is a list of 2-vectors. Each represents the endpoints of
    # an interior interval of a polygon.
    # x is an array of x-coordinates of vertices.
    #
    # Retains only the intervals containing at least one vertex.
    between <- function(i) {
      1 == max(mapply(function(a,b) a && b, i[1] <= x, x <= i[2]))
    }
    is.good <- lapply(intervals$x, between)
    list(y=y, x=intervals$x[unlist(is.good)])
    #intervals
  }
  #
  # Group the vertices by common y-coordinate.
  #
  vertices.x <- split(p$v[, "x"], p$v[, "y"])
  vertices.y <- lapply(split(p$v[, "y"], p$v[, "y"]), max)
  #
  # The "state" is a collection of segments and an index into edges.
  # It will updated during the vertical line sweep.
  #
  state <- list(level=-Inf, current=c(), i=1, x=c(), interior=c())
  #
  # Sweep vertically from bottom to top, processing the intersection
  # as we go.
  #
  mapply(function(x,y) process(update(y), x, y), vertices.x, vertices.y)
}


scale <- 10
p.raw = list(scale * cbind(x=c(0:10,7,6,0), y=c(3,0,0,-1,-1,-1,0,-0.5,0.75,1,4,1.5,0.5,3)),
             scale *cbind(x=c(1,1,2.4,2,4,4,4,4,2,1), y=c(0,1,2,1,1,0,-0.5,1,1,0)),
             scale *cbind(x=c(6,7,6,6), y=c(.5,2,3,.5)))

#p.raw = list(cbind(x=c(0,2,1,1/2,0), y=c(0,0,2,1,0)))
#p.raw = list(cbind(x=c(0, 35, 100, 65, 0), y=c(0, 50, 100, 50, 0)))

p <- as.polygon(p.raw)

results <- fetch.x(p)
#
# Find the longest.
#
dx <- matrix(unlist(results["x", ]), nrow=2)
length.max <- max(dx[2,] - dx[1,])
#
# Draw pictures.
#
segment.plot <- function(s, length.max, colors,  ...) {
  lapply(s$x, function(x) {
      col <- ifelse (diff(x) >= length.max, colors[1], colors[2])
      lines(x, rep(s$y,2), col=col, ...)
    })
}
gray <- "#f0f0f0"
grayer <- "#d0d0d0"
plot(expand(p$bb, 1.1), type="n", xlab="x", ylab="y", main="After the Scan")
sapply(1:length(p.raw), function(i) polygon(p.raw[[i]], col=c(gray, "White", grayer)[i]))
apply(results, 2, function(s) segment.plot(s, length.max, colors=c("Red", "#b8b8a8"), lwd=4))
plot(p, col="Black", lty=3)
points(p, pch=19, col=round(2 + 2*p$v[, "y"]/scale, 0))
points(p, cex=1.25)

Чи існує теорема, яка доводить, що лінія максимальної довжини всередині неопуклого багатокутника в будь-якому заданому напрямку перетинає хоча б одну вершину цього многокутника?
SS_Rebelious

@SS Так, є. Ось ескіз доказу: якщо перетину немає, то кінцеві точки відрізка лежать на внутрішніх краях ребер, і відрізок можна перемістити, принаймні трохи, вгору та вниз. Його довжина є лінійною функцією величини переміщення. Таким чином, вона може мати максимальну довжину, лише якщо довжина не змінюється при переміщенні. Це означає, що (a) це частина паралелограма, утворена сегментами максимальної довжини, і (b) і верхній, і нижній краї цього паралелограма повинні відповідати вершині, QED.
whuber

І як називається ця теорема? Я намагаюся його знайти. До речі, що з вигнутими ребрами, що не мають вершини (я маю на увазі теоретичний підхід)? Ескіз прикладу фігури, яку я маю на увазі (тупий дзвоник у формі дзвоника): "C = D".
SS_Rebelious

@SS Коли ребра зігнуті, теорема більше не виконується. Для отримання корисних результатів можуть застосовуватися методи диференціальної геометрії. Я дізнався ці методи з книги Cheeger & Ebin, « Теореми порівняння в римановій геометрії» . Однак більшість ГІС так чи інакше будуть наближати криві до детальних поліліній, тому питання (як практичне питання) є суперечливим.
whuber

Ви могли б вказати назву теореми (та сторінку, якщо можливо)? У мене книга, і я не зміг знайти необхідну теорему.
SS_Rebelious

9

Ось рішення на основі растру. Це швидко (я робив всю роботу від початку до кінця за 14 хвилин), не вимагає сценаріїв, займає лише кілька операцій і є досить точним.

Почніть з растрового зображення багатокутника. Для цього використовується сітка з 550 рядків і 1200 стовпців:

Полігон

У цьому поданні сірі (всередині) комірки мають значення 1, а всі інші комірки - NoData.

Обчисліть накопичення потоку в напрямку захід-схід, використовуючи одиничні значення комірки для вагової сітки (кількість "опадів"):

Накопичення потоку

Низьке скупчення темне, збільшується до найвищих скупчень у яскраво-жовтому.

Зональний максимум (використовуючи полігон для сітки та накопичення потоку для значень) визначає клітинку (и), де витрата найбільша. Щоб показати це, мені довелося збільшити масштаб у напрямку праворуч внизу:

Максимум

Червоні клітинки позначають кінці найвищих скупчень потоку: вони є найправішими кінцевими точками внутрішніх відрізків багатокутника максимальної довжини.

Щоб знайти ці сегменти, покладіть всю вагу на еритроцити і запустіть потік назад!

Результат

Червона смуга біля нижньої частини позначає два ряди комірок: усередині них лежить горизонтальний відрізок максимальної довжини. Використовуйте це подання як є для подальшого аналізу або перетворите його у форму полілінії (або полігону).

Існує деяка помилка дискретизації, допущена при растровому поданні. Його можна зменшити, збільшивши роздільну здатність, за деяку ціну за час обчислення.


Один із приємних аспектів цього підходу полягає в тому, що ми зазвичай знаходимо екстремальні цінності речей як частину більшого робочого процесу, в якому потрібно досягти певної мети: розміщення трубопроводу чи футбольного поля, створення екологічних буферів тощо. Процес передбачає компроміси. Таким чином, найдовша горизонтальна лінія може не бути частиною оптимального рішення. Нам, можливо, все одно, щоб знати, де лежать майже найдовші лінії. Це просто: замість вибору максимального зонального потоку виберіть усі комірки, близькі до зонального максимуму. У цьому прикладі зональний максимум дорівнює 744 (кількість стовпців, що охоплюються найдовшим внутрішнім сегментом). Натомість виберемо всі клітини в межах 5% від цього максимуму:

Вибрані майже оптимальні клітини

Проведення потоку зі сходу на захід створює цю колекцію горизонтальних сегментів:

Близько оптимальні рішення

Це карта місць, де безперебійна величина схід-захід становить 95% або більше, ніж максимальна величина схід-захід де-небудь в межах полігону.


3

Добре. У мене є ще одна (краща) ідея ( ідея №2 ). Але я вважаю, що краще реалізуватися як сценарій python, а не як SQL-querry. Знову ж таки, поширений випадок, а не лише EW.

Вам буде потрібно обмежувальне поле для багатокутника і азимут (А) як ваш напрямок вимірювання. Припустимо, що довжина ребер BBox дорівнює LA та LB. Максимально можливу відстань (MD) в межах багатокутника: MB = (LA^2 * LB^2)^(1/2)так шукає значення (V) не більш , ніж МБ: V <= MB.

  1. Починаючи з будь-якої вершини BBox, створіть лінію (LL) довжиною MB і азимутом A.
  2. Перетинають лінію LL з багатокутником, щоб отримати лінію перетину (IL)
  3. Перевірте геометрію ІЛ - якщо в лінії ІЛ лише дві точки, то обчисліть її довжину. Якщо 4 і більше - обчисліть відрізки і підберіть довжину найдовшої. Нуль (взагалі немає перехрестя) - ігноруйте.
  4. Продовжуйте створювати інші лінії LL, рухаючись від стартової точки проти або за годинниковою стрілкою до країв BBox, поки ви не закінчитеся в початковій точці (ви зробите весь цикл через BBox).
  5. Підберіть найбільше значення довжини IL (насправді вам не потрібно зберігати всі довжини, ви можете зберігати максимальне значення "поки що" під час циклу) - це буде те, чого ви прагнете.

Це звучить як подвійний цикл над вершинами: це недостатньо ефективно, щоб його уникали (за винятком дуже спрощених багатокутників).
whuber

@whuber, тут я не бачу зайвих циклів. Існує лише якась безглузда обробка двох сторін ВВ, яка не дасть нічого, крім нулів. Але ця обробка була виключена в сценарії, який я надав у відповіді, яку тут було видалено (схоже, це коментар зараз, але я не бачу це як коментар - лише як видалену відповідь)
SS_Rebelious

(1) Це третій коментар до питання. (2) Ви маєте рацію: прочитавши ваш опис дуже уважно, мені здається, що ви знаходите найдовший відрізок між (чотирма) вершинами граничного поля та вершинами багатокутника. Я не бачу, як це дає відповідь на питання: результат безумовно - не те, чого прагнула ОП.
whuber

Запропонований алгоритм @whuber знаходить найдовший перетин багатокутника з лінією, що представляє заданий напрямок. Мабуть, результат - це те, що було задано, якщо відстань між лініями перетину -> 0 або воно проходить усі вершини (для не вигнутих фігур).
SS_Rebelious

3

Я не впевнений, що відповідь Fetzer - це те, що ви хочете зробити, але так st_box2d може виконати роботу.

Ідея SS_Rebelious № 1 працюватиме у багатьох випадках, але не для деяких увігнутих багатокутників.

Я думаю, що ви повинні створити штучні lw-лінії, точки яких слідують за ребрами, коли лінії, виконані вершинами, перетинають межі полігона, якщо є можливість лінії схід-захід. приклад, коли це не буде працювати

Для цього ви можете спробувати скласти багатокутник із 4 вузлами, де довжина лінії велика, зробіть багатокутник P *, який є попереднім перекриттям з вами оригінальним багатокутником, і подивіться, чи залишають min (y1) та max (y2) деяку x-лінію можливість. (де y1 - сукупність точки між лівим верхнім корнетом та правою верхньою куткою, а y2 - у між між лівим і нижнім правою кутами 4-х вузлів багатокутника). Це не так просто, сподіваюся, ви знайдете інструменти psql, які допоможуть вам!


Це на правильному шляху. Серед перетинів із внутрішністю полігону знайдеться найдовший відрізок EW з горизонтальними лініями, що проходять через вершини багатокутника. Для цього потрібен код для переходу на вершини. Існує альтернативний (але еквівалентний) метод, дотримуючись штучного потоку на схід-захід через растрове подання полігону: максимальна довжина потоку, виявлена ​​в полігоні (що є однією з його "зональних статистичних даних"), - бажана ширина. Растровий розчин одержують всього в 3 або 4 етапи і не вимагає циклічного чи сценаріального циклу.
whuber

@Aname, додайте "№1" до "ідеї SS_Rebelious", щоб уникнути непорозумінь: я додав ще одну пропозицію. Я не можу самостійно відредагувати вашу відповідь, оскільки ця зміна становить менше 6 символів.
SS_Rebelious

1

У мене є ідея №1 ( Редагувати: для загальних випадків не тільки напрям EW, а з деякими обмеженнями, які описані в коментарях). Я не надам код, просто поняття. "Х-напрямок" - це фактично азимут, який обчислюється ST_Azimuth. Запропоновані кроки:

  1. Витягніть всі вершини з багатокутника у вигляді точок.
  2. Створіть лінії між кожною парою точок.
  3. Виберіть лінії (давайте назвемо їх lw-рядки), які знаходяться в межах початкового багатокутника (нам не потрібні лінії, які будуть перетинати межі полігону).
  4. Знайдіть відстані та азимути для кожної lw-лінії.
  5. Виберіть найдовшу відстань від lw-ліній, де азимут дорівнює шуканому азимуту або лежить на деякому інтервалі (можливо, жоден азимут не буде точно рівний шуканому азимуту).

Це не спрацює навіть для деяких трикутників , таких як вершина (0,0), (1000, 1000) та (501, 499). Його максимальна ширина схід-захід приблизно 2; азимути - близько 45 градусів; і незалежно від цього, найкоротший відрізок лінії між вершинами в 350 разів довший ширини схід-захід.
whuber

@whuber, ви праві, це не вдасться для трикутників, але для багатокутників, що представляють деякі особливості природи, це може бути корисним.
SS_Rebelious

1
Важко порекомендувати процедуру, яка різко виходить з ладу навіть для простих випадків, сподіваючись, що іноді вона може отримати правильну відповідь!
whuber

@whuber, тому не рекомендую! ;-) Я запропонував це рішення, оскільки відповіді на це питання не було. Зауважте, що ви можете опублікувати свою кращу відповідь. До речі, якщо ви розмістите кілька точок на краях трикутника, моя пропозиція спрацює ;-)
SS_Rebelious

Я запропонував кілька підходів. Растровий розміщений на веб- сайті gis.stackexchange.com/questions/32552/… та розроблений на forums.esri.com/Thread.asp?c=93&f=982&t=107703&mc=3 . Ще одна - не зовсім застосовна, але з цікавим використанням - знаходиться на gis.stackexchange.com/questions/23664/… (перетворення радону). Це проілюстровано на сайті stats.stackexchange.com/a/33102 .
whuber

1

Погляньте на моє запитання та відповідь із Злого Генія.

Сподіваємось, ваш озерний багатокутник має ряд точок, ви можете створювати лінії на цих точках за допомогою азимуту (аспект, гео напрям). Виберіть довжину рядків досить велику (частина ST_MakePoint), щоб ви могли обчислити найкоротшу лінію між двома найвіддаленішими лініями.

Ось приклад:

введіть тут опис зображення

На прикладі показана максимальна ширина багатокутника. Я вибираю для цього підходу ST_ShortestLine (червона лінія). ST_MakeLine збільшив би значення (синя лінія), а кінцева точка лінії (внизу зліва) потрапила б у синю лінію багатокутника. Ви повинні обчислити відстань із центроїдами створених (довідкових) ліній.

Ідея неправильних або увігнутих багатокутників для цього підходу. Можливо, вам доведеться перетинати полігон з растром.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.