Первая попытка решения методом грубой силы может выглядеть примерно так:
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;
Я говорю грубой силой, потому что:
Отдельные подполигоны не являютсяиндексируется, поэтому это решение не использует пространственную индексацию.Если производительность достаточно важна, возможно, стоит разбить ваши мультиполигоны на составляющие их подполигоны (с одной строкой в исходной таблице на подполигон), чтобы вы могли использовать другое решение, использующее преимущества пространственной индексации.Вы можете сделать это либо заранее (изменив дизайн исходной таблицы), либо за сценой (возможно, используя материализованное представление на основе исходной таблицы).
Похоже, что вынаходятся в Oracle XE и поэтому ограничены подмножеством Locator функциональных возможностей Oracle Spatial.
Элементы 1 и 2 означают, что ваш единственный встроенный выбор для определения взаимодействующих подполигоновс маской кажется через SDO_GEOM.SDO_DISTANCE.Это будет ресурсоемким (так как он будет вызываться для каждого подполигона) и дает вам только один тип взаимодействия по сравнению со многими возможными с помощью встроенных пространственных операторов (которые полагаются на пространственную индексацию).
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)
--------------------------------------------------------------------------------
Надеюсь, это поможет.