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)
Creating linestrings from points
UPDATED: Fix in Order By and addition of second example.
Here are some examples of how to construct linestrings from points stored in tables in two different formats.
XYZ Values in SDO_POINT of SDO_GEOMETRY object
The following example creates SDO_GEOMETRY point objects (2D) and stores them in a table linepoints. These points described individual features (identified by the column feature_id). The points are correctly ordered by the point_id column.
DROP TABLE linepoints; -- Result TABLE LINEPOINTS dropped. CREATE TABLE linepoints AS SELECT CASE WHEN trunc(level / 7) = 0 THEN 398639 ELSE 2215595 END AS feature_id, ROW_NUMBER() OVER (partition BY 1 ORDER BY rownum) AS point_id, sdo_geometry(2001,NULL, sdo_point_type(round(dbms_random.VALUE(10000,19999),3), round(dbms_random.VALUE(20000,29999),3), NULL),NULL,NULL) AS pointGeom FROM dual CONNECT BY LEVEL < 13; -- Result TABLE LINEPOINTS created. -- Select one feature's worth... SELECT a.feature_id, a.point_id, a.pointGeom FROM linepoints a WHERE a.feature_id = 398639; -- Results FEATURE_ID POINT_ID POINTGEOM ---------- -------- -------------------------------------------------------------------------- 398639 1 SDO_GEOMETRY(2001,NULL,SDO_POINT_TYPE(19674.833,22929.276,NULL),NULL,NULL) 398639 2 SDO_GEOMETRY(2001,NULL,SDO_POINT_TYPE(15015.917,26297.82,NULL),NULL,NULL) 398639 3 SDO_GEOMETRY(2001,NULL,SDO_POINT_TYPE(15917.343,28141.968,NULL),NULL,NULL) 398639 4 SDO_GEOMETRY(2001,NULL,SDO_POINT_TYPE(16322.858,20066.442,NULL),NULL,NULL) 398639 5 SDO_GEOMETRY(2001,NULL,SDO_POINT_TYPE(14752.7,26373.809,NULL),NULL,NULL) 398639 6 SDO_GEOMETRY(2001,NULL,SDO_POINT_TYPE(16154.323,25280.283,NULL),NULL,NULL) . 6 ROWS selected
Secondly, given this table linepoints here is how I would create linear (2002) sdo_geometry objects:
SELECT feature_id, substr(sdo_geom.validate_geometry(linestring,0.005),1,5) AS vLine, linestring FROM (SELECT c.feature_id, mdsys.sdo_geometry(2002,NULL,NULL, mdsys.sdo_elem_info_array(1,2,1), CAST(MULTISET(SELECT b.COLUMN_VALUE FROM linepoints a, TABLE(mdsys.sdo_ordinate_array(a.pointGeom.sdo_point.x, a.pointGeom.sdo_point.y)) b WHERE a.feature_id = c.feature_id ORDER BY a.point_id, rownum) AS mdsys.sdo_ordinate_array)) AS linestring FROM linepoints c GROUP BY c.feature_id ORDER BY c.feature_id ) f; -- Results FEATURE_ID VLINE LINESTRING ---------- ----- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 398639 TRUE SDO_GEOMETRY(2002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(11381.777,29179.921,15533.654,22883.293,14257.442,22215.899,18098.61,29694.596,19875.69,29429.811,16936.329,23639.846)) 2215595 TRUE SDO_GEOMETRY(2002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(19300.099,21279.124,14874.566,25400.551,11572.547,23158.262,15915.272,21011.269,19665.059,22354.97,16725.616,28165.866))
A good result.
Note that the ORDER BY a.point_id, rownum clause in the CAST(MULTISET(SELECT… are needed to ensure correct ordering of the points and their X,Y values when being collected into the SDO_ORDINATE_ARRAY of the resultant linestring.
XYZ Values in Individual Columns
The following example assumes the ordinate data are in separate columns in a table rather than in the SDO_POINT_TYPE SDO_GEOMETRY structure.
Firstly let’s create some test data.
DROP TABLE line_points; -- Result TABLE LINE_POINTS dropped. CREATE TABLE line_points AS SELECT trunc(level/5)+1 AS feature_id, ROW_NUMBER() OVER (partition BY 1 ORDER BY rownum) AS point_id, round(dbms_random.VALUE(10000,20000),3) AS x, round(dbms_random.VALUE(30000,40000),3) AS y, round(dbms_random.VALUE(-100,100),1) AS z FROM dual CONNECT BY LEVEL < 100; -- Result TABLE LINE_POINTS created. -- Select one feature's worth... SELECT a.feature_id, a.point_id, a.x, a.y, a.z FROM line_points a WHERE a.feature_id = 1; -- Result FEATURE_ID POINT_ID X Y Z ---------- -------- --------- --------- ----- 1 1 14245.355 39103.198 -56.4 1 2 13611.439 39075.327 57.2 1 3 19677.775 32157.407 91.2 1 4 19148.487 39934.174 -7.8
Now let’s build the 3D linestring.
SELECT feature_id, substr(sdo_geom.validate_geometry(linestring,0.005),1,10) AS vLine, linestring FROM (SELECT a.feature_id, mdsys.sdo_geometry(3002,NULL,NULL, mdsys.sdo_elem_info_array(1,2,1), CAST(MULTISET(SELECT b.COLUMN_VALUE FROM line_points b, TABLE(mdsys.sdo_ordinate_array(b.x,b.y,b.z)) b WHERE b.feature_id = a.feature_id ORDER BY b.point_id, rownum) AS mdsys.sdo_ordinate_array)) AS LineString FROM line_points a GROUP BY a.feature_id ORDER BY a.feature_id ) f; -- Result FEATURE_ID VLINE LINESTRING ---------- ----- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(10834.967,30240.895,-15.2,11277.951,39088.68,-43.2,12186.848,38194.666,-83.7,16531.394,34999.423,38.7)) 2 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(12762.782,36113.949,84.6,10840.308,36369.348,64.1,18131.782,30854.663,-62.3,16727.793,39623.237,83.7,17867.121,34401.128,-86.3)) 3 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(17002.407,39531.838,-27.1,15454.69,33234.52,84.9,14253.969,33251.42,-52.4,19832.06,35341.975,-66.8,15774.957,35213.841,-55.5)) 4 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(12469.867,36990.592,-40.8,15568.675,33472.239,-32.8,10684.001,33537.21,0.2,19862.667,37460.655,90,12262.616,38702.088,-7.2)) 5 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(14928.194,38280.358,72.4,16483.747,37641.538,-71.4,10060.866,30785.363,65,19311.863,32594.842,-70.9,10887.833,36615.265,-68.3)) 6 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(10430.269,30601.649,56.9,14843.597,32296.468,-38.1,12545.397,38551.122,58.8,15699.728,36865.074,39.8,13140.555,37717.306,-61.3)) 7 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(13887.14,39182.163,-69.4,10998.301,36315.807,-40.3,13088.562,35835.823,20,10476.982,31781.73,91.7,14414.514,36456.508,-98.2)) 8 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(14945.188,31114.27,-17.2,12857.532,34706.264,95.1,12593.085,34808.013,45.1,12580.36,30627.921,2.9,15613.011,39624.302,7.2)) 9 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(13365.794,33948.006,99.4,19782.622,30310.164,78.2,14439.438,33976.395,-51,17582.394,30907.25,-52.3,17430.688,39258.111,75.1)) 10 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(13182.98,37490.586,93.3,12077.195,38557.26,-68.6,16749.617,35733.641,-49.5,19189.818,36467.5,96.2,16677.211,36611.312,18.8)) 11 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(18342.358,36454.356,95.7,15966.729,30259.604,-58.2,18496.083,38853.952,-91.3,12538.593,32527.582,-59.6,16522.237,30288.221,-20.7)) 12 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(18510.1,35776.065,-54,16918.603,34657.555,83.7,16716.77,32362.628,7.2,17884.163,32555.611,-91.7,19777.609,36459.833,38.4)) 13 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(14850.759,32781.795,-91.4,12234.918,33549.123,-76.7,14475.272,35926.771,62.2,19185.88,35721.572,-99.6,11686.912,38599.432,76.9)) 14 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(15535.712,35259.717,-69.8,14823.918,36108.42,-77.5,18995.265,33393.98,79.5,11298.053,36226.521,80.2,10199.336,35744.338,34.4)) 15 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(19013.37,33346.841,-67.3,10863.654,34773.51,21.5,13188.374,30997.509,24.3,12076.438,37695.98,-70,12316.767,38605.515,-34.9)) 16 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(18030.662,32252.482,52.4,16867.649,32708.082,73.3,11540.562,38772.874,97.1,15895.416,36148.811,80.2,19440.718,32434.254,85.9)) 17 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(17886.291,33488.643,85.5,19747.81,30049.534,-90.1,16094.872,34875.287,91.9,15060.472,37612.15,-40.9,13007.343,37140.685,-5.7)) 18 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(14382.043,37025.927,12.9,16596.284,38165.701,78.7,17673.999,31739.898,-9.7,16573.251,34908.787,89.9,10644.063,30304.372,44.2)) 19 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(15370.166,31074.666,-10.3,15488.603,31824.248,54.9,11992.719,38411.639,-30.4,12853.929,33091.134,97.3,10578.041,39874.991,97)) 20 TRUE SDO_GEOMETRY(3002,NULL,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(13377.967,35922.605,16,15500.276,32491.701,-13.7,17942.919,37114.717,-16.5,13810.673,34459.542,67.9,18769.264,30391.873,-92.9)) -- 20 ROWS selected
Again, note that the ORDER BY a.point_id, rownum clause in the CAST(MULTISET(SELECT… are needed to ensure correct ordering of the points and their X,Y values when being collected into the SDO_ORDINATE_ARRAY of the resultant linestring.
Both these methods are simple, direct and effective. And, in my view, superior to writing PL/SQL.
I hope this is of use to someone.
Jose Sanchez
The following is my solution to Jose’s example.
WITH line_points AS ( SELECT 1 AS feature_id, 1 AS point_id,470532.39 AS X,145290.99 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 2 AS point_id,470532.39 AS X,145290.99 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 3 AS point_id,470532.38 AS X,145291.02 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 4 AS point_id,470532.38 AS X,145291.06 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 5 AS point_id,470532.43 AS X,145291.14 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 6 AS point_id,470532.51 AS X,145291.20 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 7 AS point_id,470532.59 AS X,145291.18 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 8 AS point_id,470532.67 AS X,145291.14 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 9 AS point_id,470532.68 AS X,145291.10 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 10 AS point_id,470532.68 AS X,145291.07 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 11 AS point_id,470532.56 AS X,145291.04 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 12 AS point_id,470531.41 AS X,145291.25 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 13 AS point_id,470238.55 AS X,145400.22 AS Y FROM dual UNION ALL SELECT 1 AS feature_id, 14 AS point_id,470014.12 AS X,145887.29 AS Y FROM dual ) SELECT feature_id, substr(sdo_geom.validate_geometry_with_context(linestring,0.005),1,10) AS vLine, linestring FROM (SELECT a.feature_id, sdo_util.Remove_Duplicate_Vertices( mdsys.sdo_geometry(2002,27700,NULL, mdsys.sdo_elem_info_array(1,2,1), CAST(MULTISET(SELECT b.COLUMN_VALUE FROM line_points b, TABLE(mdsys.sdo_ordinate_array(b.x,b.y)) b WHERE b.feature_id = a.feature_id ORDER BY b.point_id) AS mdsys.sdo_ordinate_array)), 0.005) AS LineString FROM line_points a GROUP BY a.feature_id ORDER BY a.feature_id ) f; -- Result FEATURE_ID VLINE LINESTRING ---------- ---------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1 TRUE SDO_GEOMETRY(2002,27700,NULL,SDO_ELEM_INFO_ARRAY(1,2,1),SDO_ORDINATE_ARRAY(470532.39,145290.99,470532.38,145291.02,470532.38,145291.06,470532.43,145291.14,470532.51,145291.2,470532.59,145291.18,470532.67,145291.14,470532.68,145291.1,470532.68,145291.07,470532.56,145291.04,470531.41,145291.25,470238.55,145400.22,470014.12,145887.29))
Hopefully, that solves your problem.
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