Top 5 Recent Articles
ARTICLES CATEGORIES
- Algorithms (22)
- All (399)
- Biography (1)
- Blog (44)
- Business Requirements (1)
- Commentary (1)
- Conversion (2)
- Customers (2)
- Data Models (1)
- Education (2)
- GeoRaptor (13)
- GPS (1)
- Image Processing (2)
- Import Export (8)
- Licensing (2)
- LiDAR (1)
- Linear Referencing (4)
- Manifold GIS (3)
- Mapping (1)
- MySQL Spatial (7)
- Networking and Routing (including Optimization) (5)
- Open Source (18)
- Oracle Spatial and Locator (194)
- Partitioning (1)
- PostGIS (36)
- Projections (1)
- Published Articles (1)
- qGIS (1)
- Recommendations (1)
- Services (1)
- Software Change Log (1)
- Source Code (37)
- Space Curves (9)
- Spatial Database Functions (109)
- Spatial DB comparison (1)
- Spatial XML Processing (11)
- SQL Server Spatial (92)
- Standards (3)
- Stored Procedure (17)
- Tessellation or Gridding (10)
- Tools (2)
- Topological Relationships (1)
- Training (2)
- Triangulation (2)
Splitting a polygon using one or more linestrings
One of the geoprocessing functions that seems to be poorly implemented is the ability to clip a polygon using one or more linestrings such that the result is a number of polygons.
Here is an example of someone asking for help on the Oracle Technology Network’s Spatial forum:
I have a task where i have to draw a 30 meter buffer around roads feature class and wherever it comes across intersection there that buffer should be splitted according with intersection, for example if it is T inetersect, then polygon should be splitted in three piece, or if it has four exit points, then it should be splitted in four piece, please anyone can guide me how can i achieve this task?
Here is an example “T” intersection:
SELECT 'Line' AS ltype, sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,0,5,5)) AS geom FROM dual UNION ALL SELECT 'IntLine1' AS ltype, sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(0,5,5,5)) AS geom FROM dual UNION ALL SELECT 'IntLine2' AS ltype, sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,5,10,5)) AS geom FROM dual; -- Results -- LTYPE GEOM -------- ------------------------------------------------------------------------------------------------------ Line MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(5,0,5,5)) IntLine1 MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(0,5,5,5)) IntLine2 MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(5,5,10,5))
These look like this:
The polygon will be created by buffering “Line” by 3 meters. In order to correctly cut the buffered polygon as the questioner requires, we need to extend “Line” at its start by more than 3 meters. The buffering will be done by my Spatial Companion 4 Oracle (SC4O) ST_Buffer rather than Oracle’s SDO_GEOM.SDO_BUFFER but the latter could be used as easily. The extension of “Line” at its start is done by my GEOM.EXTEND function (see free pl/sql packages).
SELECT 'LineExtend' AS ltype, codesys.GEOM.extend(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,0,5,5)),3,0.005,'START') AS geom FROM dual UNION ALL SELECT 'PolyBuff' AS ltype, codesys.sc4o.st_buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,0,5,5)),3,2) AS buff FROM dual; -- Results -- LTYPE GEOM ---------- ------------------------------------------------------------------------------------------------------ LineExtend MDSYS.SDO_GEOMETRY(2002,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1),MDSYS.SDO_ORDINATE_ARRAY(5,-3,5,5)) PolyBuff MDSYS.SDO_GEOMETRY(2003,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1),MDSYS.SDO_ORDINATE_ARRAY(2,5,2,0,2.06,-0.59,2.23,-1.15,2.51,-1.67,2.88,-2.12,3.33,-2.49,3.85,-2.77,4.41,-2.94,5,-3,5.59,-2.94,6.15,-2.77,6.67,-2.49,7.12,-2.12,7.49,-1.67,7.77,-1.15,7.94,-0.59,8,0,8,5,7.94,5.59,7.77,6.15,7.49,6.67,7.12,7.12,6.67,7.49,6.15,7.77,5.59,7.94,5,8,4.41,7.94,3.85,7.77,3.33,7.49,2.88,7.12,2.51,6.67,2.23,6.15,2.06,5.59,2,5))
The result of the extend (red dash lines) and the buffer can be seen here:
We now have the components for splitting a (buffered) polygon with a set of lines.
One might think that if we simply collect the linestrings in to a single multilinestring and use it to clip the buffered polygon using SDO_GEOM.SDO_INTERSECTION we will have the right result. But this will not happen because SDO_INTERSECTION:
Returns a geometry object that is the topological intersection (AND operation) of two geometry objects.
In other words it will clip the lines and return them as they are the only common elements of the two objects. (In the image below note the lines are wholly within the buffer.
Similarly, SDO_XOR, SDO_DIFFERENCE etc all do not work.
So, how do we do this?
My approach is as follows (includes steps already done):
1. Buffer “Line” by 3 meters;
2. Extend “Line” at start by 3 meters;
3. Intersect (clip) all three lines with buffered polygon;
4. Convert buffered polygon into a linestring (outer boundary);
5. Pump collected set of linestring into the Java Topology Suite’s (JTS) PolygonBuilder routine exposed via my SC4O.ST_PolygonBuilder function. This function will build a set of polygons from the input lines.
Here is the SQL:
SELECT codesys.sc4o.ST_PolygonBuilder( codesys.T_GeometrySet( codesys.sc4o.st_intersection(c.mLines, codesys.sc4o.st_buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,0,5,5)),3,2), 3)),3) AS RESULT FROM (SELECT sdo_aggr_concat_lines(b.geom) AS mLines FROM (SELECT 'LineExtend' AS ltype, codesys.GEOM.extend(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,0,5,5)),3,0.005,'START') AS geom FROM dual UNION ALL SELECT 'IntLine1' AS ltype, sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(0,5,5,5)) AS geom FROM dual UNION ALL SELECT 'IntLine2' AS ltype, sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,5,10,5)) AS geom FROM dual UNION ALL SELECT 'buffer' AS ltype, sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),a.buff.sdo_ordinates) AS geom FROM (SELECT codesys.sc4o.st_buffer(sdo_geometry(2002,NULL,NULL,sdo_elem_info_array(1,2,1),sdo_ordinate_array(5,0,5,5)),3,2) AS buff FROM dual ) a ) b ) c; -- Result -- RESULT ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MDSYS.SDO_GEOMETRY(2007,NULL,NULL,MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1,39,1003,1,63,1003,1),MDSYS.SDO_ORDINATE_ARRAY(7.12,7.12,6.67,7.49,6.15,7.77,5.59,7.94,5,8,4.41,7.94,3.85,7.77,3.33,7.49,2.88,7.12,2.51,6.67,2.23,6.15,2.06,5.59,2,5,5,5,8,5,7.94,5.59,7.77,6.15,7.49,6.67,7.12,7.12,7.77,-1.15,7.94,-0.59,8,0,8,5,5,5,5,-3,5.59,-2.94,6.15,-2.77,6.67,-2.49,7.12,-2.12,7.49,-1.67,7.77,-1.15,2,0,2.06,-0.59,2.23,-1.15,2.51,-1.67,2.88,-2.12,3.33,-2.49,3.85,-2.77,4.41,-2.94,5,-3,5,5,2,5,2,0))
This looks like this:
Which very much looks like the correct result.
I hope this helps someone.
Documentation
- MySQL Spatial General Functions
- Oracle LRS Objects
- Oracle Spatial Exporter (Java + pl/SQL)
- Oracle Spatial Object Functions
- Oracle Spatial Object Functions (Multi Page)
- PostGIS pl/pgSQL Functions
- SC4O Oracle Java Topology Suite (Java + pl/SQL)
- SQL Server Spatial General TSQL Functions
- SQL Server Spatial LRS TSQL Functions