как получить небольшую часть коллекции полигонов оракула - PullRequest
2 голосов
/ 06 июня 2011

У меня есть SDO_GEOMETRY столбец , содержащий довольно большие мульти-полигоны , определенные следующим образом:

INSERT INTO t1 (i, d, g)
VALUES (
  25,
  'Multipolygon - multi-touch',
  sdo_geometry (2007, null, null, sdo_elem_info_array (1,1003,1, 17,1003,1), 
  sdo_ordinate_array (50,95, 55,95, 53,96, 55,97, 53,98, 55,99, 50,99, 50,95, 55,100, 55,95, 60,95, 60,100, 55,100))
);

Вместо двух полигонов, как вВ приведенном выше примере один столбец содержит> 100 полигонов.

Я бы хотел отфильтровать этот столбец , чтобы он возвращал только соответствующее подмножество (используя bbox?), что-то вроде:

  SELECT filter(Geometry, bbox) from Table Where Id = 1

1 Ответ

4 голосов
/ 08 июня 2011

Первая попытка решения методом грубой силы может выглядеть примерно так:

CREATE OR REPLACE FUNCTION FILTER_MULTI_POLYGONS
(
    udtGeometry IN SDO_GEOMETRY,
    udtMask IN SDO_GEOMETRY,
    dTolerance IN NUMBER
)
RETURN SDO_GEOMETRY
AS
    iElements INTEGER;
    udtElement SDO_GEOMETRY;
    udtResult SDO_GEOMETRY := NULL;
    iCount INTEGER;
BEGIN
    IF udtGeometry IS NOT NULL THEN
        iElements := SDO_UTIL.GETNUMELEM(udtGeometry);
        FOR iElement IN 1..iElements
        LOOP
            udtElement := SDO_UTIL.EXTRACT(udtGeometry, iElement);
            IF SDO_GEOM.SDO_DISTANCE(udtElement, udtMask, dTolerance) <= dTolerance THEN
                IF udtResult IS NULL THEN
                    udtResult := udtElement;
                ELSE
                    udtResult := SDO_UTIL.APPEND(udtResult, udtElement);
                END IF;
            END IF;
        END LOOP;
    END IF;
    RETURN udtResult;
END;

Я говорю грубой силой, потому что:

  1. Отдельные подполигоны не являютсяиндексируется, поэтому это решение не использует пространственную индексацию.Если производительность достаточно важна, возможно, стоит разбить ваши мультиполигоны на составляющие их подполигоны (с одной строкой в ​​исходной таблице на подполигон), чтобы вы могли использовать другое решение, использующее преимущества пространственной индексации.Вы можете сделать это либо заранее (изменив дизайн исходной таблицы), либо за сценой (возможно, используя материализованное представление на основе исходной таблицы).

  2. Похоже, что вынаходятся в Oracle XE и поэтому ограничены подмножеством Locator функциональных возможностей Oracle Spatial.

  3. Элементы 1 и 2 означают, что ваш единственный встроенный выбор для определения взаимодействующих подполигоновс маской кажется через SDO_GEOM.SDO_DISTANCE.Это будет ресурсоемким (так как он будет вызываться для каждого подполигона) и дает вам только один тип взаимодействия по сравнению со многими возможными с помощью встроенных пространственных операторов (которые полагаются на пространственную индексацию).

  4. SDO_UTIL.APPEND, возможно, не самый эффективный (или правильный, особенно если ваши мультиполигоны не пересекаются) для построения «отфильтрованного» многогранного результата, но этоиллюстрирует концепцию.

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

SQL> REM Example mask that overlaps first polygon only
SQL> SELECT 
  2      FILTER_MULTI_POLYGONS
  3      (
  4          T1.G, 
  5          SDO_GEOMETRY
  6          (
  7              2003, 
  8              NULL, 
  9              NULL, 
 10              SDO_ELEM_INFO_ARRAY(1, 1003, 3),
 11              SDO_ORDINATE_ARRAY(0, 0, 53, 96)
 12          ),
 13          0.1
 14      ) AS RESULT
 15  FROM T1;

RESULT(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARR
AY(50, 95, 55, 95, 53, 96, 55, 97, 53, 98, 55, 99, 50, 99, 50, 95))


SQL> REM Example mask that overlaps second polygon only
SQL> SELECT 
  2      FILTER_MULTI_POLYGONS
  3      (
  4          T1.G, 
  5          SDO_GEOMETRY
  6          (
  7              2003, 
  8              NULL, 
  9              NULL, 
 10              SDO_ELEM_INFO_ARRAY(1, 1003, 3),
 11              SDO_ORDINATE_ARRAY(56, 0, 60, 96)
 12          ),
 13          0.1
 14      ) AS RESULT
 15  FROM T1;

RESULT(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
SDO_GEOMETRY(2003, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARR
AY(55, 100, 55, 95, 60, 95, 60, 100, 55, 100))


SQL> REM Example mask that overlaps both polygons
SQL> SELECT 
  2      FILTER_MULTI_POLYGONS
  3      (
  4          T1.G, 
  5          SDO_GEOMETRY
  6          (
  7              2003, 
  8              NULL, 
  9              NULL, 
 10              SDO_ELEM_INFO_ARRAY(1, 1003, 3),
 11              SDO_ORDINATE_ARRAY(0, 0, 100, 100)
 12          ),
 13          0.1
 14      ) AS RESULT
 15  FROM T1;

RESULT(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
SDO_GEOMETRY(2007, NULL, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 17, 1003, 1), SDO
_ORDINATE_ARRAY(50, 95, 55, 95, 53, 96, 55, 97, 53, 98, 55, 99, 50, 99, 50, 95,
55, 100, 55, 95, 60, 95, 60, 100, 55, 100))


SQL> REM Example mask that overlaps neither polygon
SQL> SELECT 
  2      FILTER_MULTI_POLYGONS
  3      (
  4          T1.G, 
  5          SDO_GEOMETRY
  6          (
  7              2003, 
  8              NULL, 
  9              NULL, 
 10              SDO_ELEM_INFO_ARRAY(1, 1003, 3),
 11              SDO_ORDINATE_ARRAY(0, 0, 10, 10)
 12          ),
 13          0.1
 14      ) AS RESULT
 15  FROM T1;

RESULT(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------

Надеюсь, это поможет.

...