Как замкнуть соседние линии?

Ответить
Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Как замкнуть соседние линии?

Сообщение Denis Rykov » 25 ноя 2013, 06:19

Предположим, что у нас есть несколько линий. И нам необходимо соединить их концы в случае, если они лежат в пределах определенного расстояния. Я попробовал использовать для этого v.clean:

Код: Выделить всё

v.clean input=input_line@PERMANENT output=output_line@PERMANENT type=line tool=snap thres=200
но полученный результат не устраивает по той причине, что он меняет ориентацию исходных геометрий (см. вложение). Можно ли каким-то образом замкнуть линии путём их продолжения до места пересечения?
Вложения
grass-snapping.png
grass-snapping.png (8.57 КБ) 15153 просмотра
Spatial is now, more than ever, just another column- The Geometry Column.

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 25 ноя 2013, 09:00

Вот так сходу этого сделать нельзя. Надо подумать :)
Редактор материалов, модератор форума

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Как замкнуть соседние линии?

Сообщение Denis Rykov » 25 ноя 2013, 09:30

Может быть стоит перенести тему в Общие? Просто я подумал, что в GRASS точно должен быть нужный инструмент.
Spatial is now, more than ever, just another column- The Geometry Column.

trir
Гуру
Сообщения: 5292
Зарегистрирован: 09 апр 2010, 19:30
Репутация: 1015
Ваше звание: просто мимо прохожу
Откуда: Ё-бург

Re: Как замкнуть соседние линии?

Сообщение trir » 25 ноя 2013, 09:43

Код: Выделить всё

FUNCTION [dbo].[LS_AddPoint]
(
	@Ls geometry,
	@np geometry
)
RETURNS geometry
AS
BEGIN
  Declare @I Integer =1, @ICount Integer;
  Declare @nStr nvarchar(max);
  Declare @crP geometry;
  Set @ICount = @Ls.STNumPoints() + 1;
  Set @nStr = 'LineString(';
  while @I < @ICount 
   begin
	Set @crP = @Ls.STPointN(@I);
	Set @nStr = Concat(@nStr, SUBSTRING(@crP.ToString(), 8, Len(@crP.ToString())-8), ',');
	--Concat(@nStr, ltrim(STR(@crP.STX, 7, 11)), ' ', ltrim(STR(@crP.STY, 99, 11)), ',');
	set @I = @I + 1;
   end;
  Set @nStr = Concat(@nStr, SUBSTRING(@nP.ToString(), 8, Len(@nP.ToString())-8), ')');
  --Concat(@nStr, ltrim(STR(@nP.STX, 99, 11)), ' ', ltrim(STR(@nP.STY, 99, 11)), ')');
  Return geometry::STGeomFromText(@nStr, 0);
END

Код: Выделить всё

FUNCTION [dbo].[LS_Union]
(
@sls geometry,
@els geometry
)
RETURNS geometry
AS
BEGIN
	-- Declare the return variable here
	DECLARE @i int = 1, @iCount int;
	DECLARE @wP geometry;
	--
	Set @ICount = @eLs.STNumPoints();
	while @I < @ICount + 1
	 begin
	   Set @wP = @eLs.STPointN(@I);
	   Set @sls = dbo.LS_AddPoint(@sls, @wP);
	   set @I = @I + 1;
	 end;
	--
	RETURN @sls;
END

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 25 ноя 2013, 09:44

Denis Rykov писал(а):Может быть стоит перенести тему в Общие? Просто я подумал, что в GRASS точно должен быть нужный инструмент.
Пусть это висит здесь, в "Общем" лучше отдельную тему создать. Кстати, очень распространённое заблуждение насчёт GRASS. :)

По-хорошему, надо писать скрипт, который будет по какому-то известному алгоритму считать точки пересечения линий на их продолжении.

А если надо по-быстрому просто соединить концы линий, то вот велосипедик:

Код: Выделить всё

# получаем вершины линий
v.to.points -v in=lns out=lns_vert
# делаем текстовый дамп вершин, фильтруем координаты и загоняем их назад в единую линию
v.out.ascii in=lns_vert | cut -d'|' -f1,2 | v.in.lines in=- out=lns_new fs='|'
Редактор материалов, модератор форума

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 25 ноя 2013, 09:46

trir, как я могу применить это в GRASS? А так да, выглядит очень круто, я просто сражён.
Редактор материалов, модератор форума

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Как замкнуть соседние линии?

Сообщение Denis Rykov » 26 ноя 2013, 12:54

Написал небольшой скрипт, который можно запустить в консоли QGIS и продолжения линий замкнуться (пока без их физического объединения). Одно ограничение: каждый сегмент должен быть пересекаем только с одним другим, то есть ситуация, когда, например, в порог попадают три и более концов разных линий не учитывается, да и непонятно в этом случае как поступать. Попробуйте, пожалуйста, кто-нибудь на своих тестовых данных. Да, и тему, думаю, нужно куда-нибудь переместить. Вот что у меня получилось в итоге:

Код: Выделить всё

FirstVertex = 0
SecondVertex = 1
LastVertex = -1
PenultVertex = -2

def calculateNodes(features, thresh):
nodes = []
for i in features[:-1]:
igeom = i.geometry().asPolyline()
for j in features[features.index(i)+1:]:
jgeom = j.geometry().asPolyline()
distances = {
'ff': pow(igeom[FirstVertex].sqrDist(jgeom[FirstVertex]), 0.5),
'fl': pow(igeom[FirstVertex].sqrDist(jgeom[LastVertex]), 0.5),
'lf': pow(igeom[LastVertex].sqrDist(jgeom[FirstVertex]), 0.5),
'll': pow(igeom[LastVertex].sqrDist(jgeom[LastVertex]), 0.5)
}
min_key = min(distances, key=distances.get)
if distances[min_key] <= thresh:
nodes.append(dict(source=i, target=j, direction=min_key))
return nodes

def getCross(source, target, direction):
geom_source = source.geometry().asPolyline()
geom_target = target.geometry().asPolyline()
if direction == 'ff':
p1,p2 = geom_source[FirstVertex], geom_source[SecondVertex]
p3,p4 = geom_target[FirstVertex], geom_target[SecondVertex]
elif direction == 'fl':
p1,p2 = geom_source[FirstVertex], geom_source[SecondVertex]
p3,p4 = geom_target[LastVertex], geom_target[PenultVertex]
elif direction == 'lf':
p1,p2 = geom_source[LastVertex], geom_source[PenultVertex]
p3,p4 = geom_target[FirstVertex], geom_target[SecondVertex]
elif direction == 'll':
p1,p2 = geom_source[LastVertex], geom_source[PenultVertex]
p3,p4 = geom_target[LastVertex], geom_target[PenultVertex]
k1 = (p2.y()-p1.y()) / (p2.x()-p1.x())
k2 = (p4.y()-p3.y()) / (p4.x()-p3.x())
b1 = p2.y() - k1*p2.x()
b2 = p4.y() - k2*p4.x()
return ((b1-b2)/(k2-k1), (k2*b1 - k1*b2)/(k2-k1)) if k1 != k2 else None

def getVertexId(feature, position):
if position == 'f':
vertexId = 0
elif position == 'l':
vertexId = len(feature.geometry().asPolyline()) - 1
return vertexId

def main():
canvas = qgis.utils.iface.mapCanvas()
layer = qgis.utils.iface.activeLayer()
features = [f for f in layer.getFeatures()]
thresh = 200
layer.startEditing()
eu = QgsVectorLayerEditUtils(layer)
canvas.refresh()
for node in calculateNodes(features, thresh):
cross = getCross(source=node['source'], target=node['target'], direction=node['direction'])
source_position = node['direction'][0]
target_position = node['direction'][1]
if cross is not None:
eu.moveVertex(cross[0], cross[1], node['source'].id(), getVertexId(node['source'], source_position))
eu.moveVertex(cross[0], cross[1], node['target'].id(), getVertexId(node['target'], target_position))
canvas.refresh()

main()
Вложения
extend_lines.png
extend_lines.png (22 КБ) 15059 просмотров
Spatial is now, more than ever, just another column- The Geometry Column.

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 03 дек 2013, 14:25

Денис, у меня скрипт отрабатывает без ошибок, но линии не объединяет. Просто делает текущий слой редактируемым. Порог менял, не помогло.
Редактор материалов, модератор форума

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Как замкнуть соседние линии?

Сообщение Denis Rykov » 05 дек 2013, 12:15

Скрипт не объединяет линии, он просто удлинняет каждую до точки пересечения, объединение - это отдельная задача. И так не делает? А данные в какой СК?
Spatial is now, more than ever, just another column- The Geometry Column.

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 06 дек 2013, 17:53

Denis Rykov писал(а):Скрипт не объединяет линии, он просто удлинняет каждую до точки пересечения, объединение - это отдельная задача. И так не делает? А данные в какой СК?
Я просто неверно выразился, имел в виду удлинение, конечно. Всё, что он делает, я написал выше, больше ничего. Пока пробовал в местной СК на базе Гаусса-Крюгера / Пулково 42. Проверю ещё и в других СК (хотя если там те же метры, то какая разница?).
Редактор материалов, модератор форума

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Как замкнуть соседние линии?

Сообщение Denis Rykov » 06 дек 2013, 18:53

А можешь данные приложить?

[ Сообщение с мобильного устройства ]
Spatial is now, more than ever, just another column- The Geometry Column.

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 06 дек 2013, 22:26

Denis Rykov писал(а):А можешь данные приложить?
Да там просто несколько линий, специально нарисованных разомкнутыми (т.е. это никакие не данные). А может быть дело в способе запуска скрипта? Я делаю в Питон-консоли " execfile '~/путь/к/скрипту' ".
Редактор материалов, модератор форума

Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3376
Зарегистрирован: 11 апр 2008, 21:09
Репутация: 529
Ваше звание: Author
Контактная информация:

Re: Как замкнуть соседние линии?

Сообщение Denis Rykov » 07 дек 2013, 11:14

Попробовал и таким способом запустить - работает.

Код: Выделить всё

execfile("/home/rykov/test.py")
Я сейчас в скрипте заметил, что пропущена одна строка (определение переменной canvas), добавил ее, но без нее вообще не работало - выводилось сообщение об ошибке. Попробуй еще раз с новой версией, может в этом дело было.
Spatial is now, more than ever, just another column- The Geometry Column.

Александр Мурый
Гуру
Сообщения: 5173
Зарегистрирован: 26 сен 2009, 16:26
Репутация: 793
Ваше звание: званий не имею
Откуда: Москва

Re: Как замкнуть соседние линии?

Сообщение Александр Мурый » 07 дек 2013, 14:46

Теперь заработало (правда, в другом проекте с другой СК). Денис, спасибо :)
Переменную "canvas" я сам добавлял, но, видимо, как-то не так.
Редактор материалов, модератор форума

Ответить

Вернуться в «GRASS»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 29 гостей