Більше

Знайдіть точку, яка потрапляє між двома паралельними прямими

Знайдіть точку, яка потрапляє між двома паралельними прямими


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

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

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

Я не знаю, як цього досягти. Хтось може мені допомогти?

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

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

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


Я спробував би нижче arcpy (навіть ручний!) Алгоритм-

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

Я б сказав, що це геометрична вправа.

ПСЕВДО-КОД:

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

Як бачимо, є окремі випадки - обведені чорні точки:

  1. Дуже звивиста дорога на 1 лінію. Цього можна усунути, а) працюючи лише з двома лініями доріг або б) переконавшись, що FID доріг, що перетинають червону крапку та зірку, відрізняються. Однак, якщо дорога з дорогою має перехрестя з іншою дорогою на 1 лінію, це може не спрацювати.
  2. Чорна точка розташована на продовженні рівно перпендикулярної 1 лінії дороги. У цьому випадку існує ймовірність того, що дорогу з 1 смугою руху можна вибрати як найближчого сусіда.
  3. Чорна точка сидить на лінії.

Усі вищезазначені випадки є малоймовірними, проте, здається, найбезпечнішим варіантом є робота лише з 2 лінійними дорогами, тобто експортувати їх до окремого класу функцій. Випадок 3 - смішний, ми залишимо це на волю випадку, оскільки найкоротша відстань до прямої ніколи не буває справжнім нулем, отже, можна знайти «протилежний» напрямок променя, що з'єднує 2 точки.

Реалізація Python:

імпорт arcpy, traceback, os, sys з arcpy імпорт env env.overwriteoutput = True # речі, які потрібно змінити --------- maxD = 30 mxd = arcpy.mapping.MapDocument ("CURRENT") pointLR = arcpy.mapping .ListLayers (mxd, "NODES") [0] lineLR = arcpy.mapping.ListLayers (mxd, "LINKS") [0] sjOneToMany = r'D:  scratch  sj2.shp 'RDNAME = "street" # - ----------------------- dDest = arcpy.Describe (lineLR) SR = dDest.spatialReference try: def showPyMessage (): arcpy.AddMessage (str (time .ctime ()) + "-" + повідомлення) g = arcpy.Geometry () geometryList = arcpy.CopyFeatures_management (pointLR, g) n = len (geometryList) endPoint = arcpy.Point () arcpy.SpatialJoin_analysis (pointLR, lineLR, sjOneToMany, "JOIN_ONE_TO_MANY", "KEEP_COMMON", "", "WITHIN_A_DISTANCE", maxD) initFidList = (- 1,) для fid в діапазоні (n): TARGET_FID "=% s"% str (fid) nearTable = arcpy.da .TableToNumPyArray (sjOneToMany, ("TARGET_FID", "JOIN_FID"), запит) if len (nearTable) <2: continue fidLines = [int (row [1]) for row in nearTable] FID "in% s"% str ( кортеж (fidLines)) listOfLines = {} blackPoint = geometryLis t [fid] з arcpy.da.SearchCursor (lineLR, ("FID", "Shape @", "STREET"), запит) як рядки: dMin = 100000 для рядка в рядках: shp = row [1]; dCur = blackPoint.distanceTo (shp) listOfLines [рядок [0]] = рядок [-2:] якщо dCur

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


Оскільки вулиці паралельні, я припустив, що вони були створені зКопіювати паралельнона панелі інструментів "Редагувати", завдяки чому пара ліній має однаковий напрямок. Потім ми можемо перебирати координати першого рядка і додавати їх до багатокутника, а потім перебирати по зворотний другого рядка. Безумовно, є кращий спосіб підійти до захоплення лінійних пар; підхід OID працює, але він не дуже гарний.

імпорт колекцій імпорт arcpy FC = "fc" points = "points" pgons = "pgons" arcpy.env.overwriteOutput = True def buildpoly (oid_coords): #create ddict of the form OID: ddict = collection.defaultdict (list) for k, v in oid_coords: ddict [k] .append (v) line1, line2 = ddict.keys () # Припустимо, що паралельні лінії мають однаковий напрямок, тому поверніть назад другий arr = arcpy .Array () arr.extend (arcpy.Point (* pt) для pt у вирішенні [line1]) arr.extend (arcpy.Point (* pt) для pt у ddict [line2] [:: - 1]) повернути arcpy .Polygon (arr) #id - це ціле поле, яке поєднує паралельні лінії разом unique = list (set (t [0] for t in arcpy.da.SearchCursor (FC, "id"))) polygons = [] for uni in унікальний: polygons.append (buildpoly ([r для r в рядку] для рядка в arcpy.da.SearchCursor (FC, ["OID @", "SHAPE @ XY"], "id = {}". format (uni) , explode_to_points = True))) arcpy.CopyFeatures_management (багатокутники, pgons)

Звідти це дзвінок Intersect / Select Layer за місцем розташування / тим, що є у вас. Зверніть увагу, щоSбагатокутник у формі не ідеальний, оскільки я намалював його від руки, і є кілька дуг, якіexplode_to_pointsне справляється належним чином. Просто біжи Ущільнити або еквівалент.