Существует ли инструмент ArcPy для изменения размера многоугольника, такой как инструмент «Масштаб» на панели инструментов «Расширенное редактирование» в ArcMap?

17

Я пишу скрипт на Python для ArcGIS 10.3. Я знаю об Scale toolинтерфейсе ArcGIS, но не могу найти такую ​​команду arcpy. Это существует?

Как вы видите на картинке, Scale toolработы отличаются от Buffer tool- это меняет форму оригинального многоугольника. Итак, вопрос:

Могу ли я использовать Scale tool(доступно из интерфейса ArcGIS) используя arcpy?

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

Мистер Че
источник
2
Как насчет буферизации и удаления старого многоугольника !? буфер может использоваться с положительными и отрицательными значениями!
Фарид Чераги
Речь идет о существующем инструменте arcpy, а не о том, как изменить размер многоугольника.
г-н Че
Ваш заголовок, вопрос и комментарий, похоже, расходятся друг с другом. Если предоставленные дублирующие вопросы не отвечают на ваш вопрос, не могли бы вы отредактировать свой вопрос, чтобы уточнить, что вам нужно?
Аарон
1
@ Mr.Che Буферный инструмент можно использовать в сценариях Python с помощью arcpy.Buffer_analysis (...)
Фарид Чераги
Это супер! Как я могу обновить каждый класс пространственных объектов числом в таблице, а не масштабировать все объекты, например, на 0,5? Спасибо
user1655130

Ответы:

27

Я не знаю ничего в arcpy API, который бы сделал масштабирование для вас, но написание функции для этого было бы относительно просто.

Приведенный ниже код выполняет масштабирование для 2D-объектов и не учитывает значения M или Z:

import arcpy
import math

def scale_geom(geom, scale, reference=None):
    """Returns geom scaled to scale %"""
    if geom is None: return None
    if reference is None:
        # we'll use the centroid if no reference point is given
        reference = geom.centroid

    refgeom = arcpy.PointGeometry(reference)
    newparts = []
    for pind in range(geom.partCount):
        part = geom.getPart(pind)
        newpart = []
        for ptind in range(part.count):
            apnt = part.getObject(ptind)
            if apnt is None:
                # polygon boundaries and holes are all returned in the same part.
                # A null point separates each ring, so just pass it on to
                # preserve the holes.
                newpart.append(apnt)
                continue
            bdist = refgeom.distanceTo(apnt)

            bpnt = arcpy.Point(reference.X + bdist, reference.Y)
            adist = refgeom.distanceTo(bpnt)
            cdist = arcpy.PointGeometry(apnt).distanceTo(bpnt)

            # Law of Cosines, angle of C given lengths of a, b and c
            angle = math.acos((adist**2 + bdist**2 - cdist**2) / (2 * adist * bdist))

            scaledist = bdist * scale

            # If the point is below the reference point then our angle
            # is actually negative
            if apnt.Y < reference.Y: angle = angle * -1

            # Create a new point that is scaledist from the origin 
            # along the x axis. Rotate that point the same amount 
            # as the original then translate it to the reference point
            scalex = scaledist * math.cos(angle) + reference.X
            scaley = scaledist * math.sin(angle) + reference.Y

            newpart.append(arcpy.Point(scalex, scaley))
        newparts.append(newpart)

    return arcpy.Geometry(geom.type, arcpy.Array(newparts), geom.spatialReference)

Вы можете назвать это с геометрией объекта, масштабный коэффициент (1 = одинакового размера, 0,5 = половина размера, 5 = 5 раз больше, и т.д.), и дополнительный опорной точки:

scale_geom(some_geom, 1.5)

Используйте это вместе с курсорами для масштабирования всего класса объектов, предполагая, что целевой класс объектов уже существует:

incur = arcpy.da.SearchCursor('some_folder/a_fgdb.gdb/orig_fc', ['OID@','SHAPE@'])
outcur = arcpy.da.InsertCursor('some_folder/a_fgdb.gdb/dest_fc', ['SHAPE@'])

for row in incur:
    # Scale each feature by 0.5 and insert into dest_fc
    outcur.insertRow([scale_geom(row[1], 0.5)])
del incur
del outcur

edit: вот пример, использующий аппроксимацию вашей тестовой геометрии, в 0,5 и 5 раз: введите описание изображения здесь

Также проверено с многокольцевыми многоугольниками (отверстиями)! введите описание изображения здесь

Объяснение по запросу:

scale_geomберет один многоугольник и проходит через каждую вершину, измеряя расстояние от нее до контрольной точки (по умолчанию, центроид многоугольника).
Это расстояние затем масштабируется в соответствии с масштабом, заданным для создания новой «масштабированной» вершины.

Масштабирование выполняется путем рисования линии по масштабированной длине от контрольной точки через исходную вершину, при этом конец линии становится масштабированной вершиной.
Здесь есть угол и угол поворота, потому что проще вычислить положение конца линии вдоль одной оси, а затем повернуть его «на место».

Злой гений
источник
1
Я проверил этот скрипт, и он отлично работает. Ты чертов гений! =) Огромное спасибо. Я оставлю этот вопрос без ответа, чтобы больше людей увидели его в «будущих вопросах».
г-н Че
1
Я обнаружил, что когда я пытаюсь обработать многоугольник с отверстием - это приводит к сбою сценария в строке bdist = refgeom.distanceTo(apnt). Можете ли вы проверить и исправить это?
г-н Че
@ Mr.Che Ой, я забыл, что ArcPy возвращает все кольца части многоугольника в одном массиве. Кольца разделены нулевыми точками. Это легко исправить, пожалуйста, смотрите редактирование.
Злой гений
Здравствуйте. Можно ли получить небольшое объяснение того, как работает скрипт, я плохо умею кодировать и не получаю все строки, поэтому он не работает для меня, пожалуйста?
питер
@peter Конечно, я добавил краткое объяснение того, что происходит. Он не предназначен для того, чтобы быть отдельным скриптом, а должен быть интегрирован в собственный скрипт. Нижний фрагмент кода показывает пример того, как его можно использовать.
Злой гений