Changes between Version 1 and Version 2 of rfc64_triangle_polyhedralsurface_tin


Ignore:
Timestamp:
Oct 30, 2016, 1:37:16 AM (8 years ago)
Author:
meier
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • rfc64_triangle_polyhedralsurface_tin

    v1 v2  
    1 TODO
     1Author: Avyav Kumar Singh [[BR]]
     2Contact: avyavkumar at gmail dot com [[BR]]
     3Status: Proposed [[BR]]
     4
     5== Summary ==
     6As of now, the OGRGeometry class (found at [http://www.gdal.org/classOGRGeometry.html]) (the base class from which all the subtypes are derived) is limited to OGRCompoundCurve, OGRCircularString, OGRLinearRing, OGRMultiLineString, OGRMultiPoint, OGRMultiPolygon, OGRMultiCurve, OGRSimpleCurve, OGRCurvePolygon and OGRPolygon. [[BR]]
     7[[BR]]
     8This RFC addresses the addition of the following new geometries in OGRGeometry - [[BR]]
     9[[BR]]
     10Triangle - A subset of polygons, the fundamental difference is that of 3 nodes only and ONLY ONE exterior boundary and NO interior polygons. [[BR]]
     11[[BR]]
     12PolyhedralSurface - A 3D figure made exclusively of Polygons.[[BR]]
     13[[BR]]
     14TriangulatedSurface - A subset of PolyhedralSurface; a 3D figure which consists exclusively of Triangles. [[BR]]
     15[[BR]]
     16== Reference documents ==
     17[[BR]]
     18The following was consulted for the geometries - [[BR]]
     19* [http://portal.opengeospatial.org/files/?artifact_id=25355]
     20* [https://github.com/postgis/postgis/blob/svn-trunk/doc/bnf-wkt.txt]
     21* [https://github.com/postgis/postgis/blob/svn-trunk/doc/bnf-wkb.txt]
     22[[BR]]
     23== Core changes ==
     24[[BR]]
     25Some prelimenary work had already been done prior to this proposal, such as including the necessary WKB codes in <ogr_core.h>.
     26Additionally, the SFCGAL library has been interfaced through OGR methods for implementing some methods from the API. For that,
     27SFCGAL methods are introduced in OGRGeometry to convert SFCGAL geometries <-> OGR geometries.
     28{{{
     29static sfcgal_geometry_t* OGRexportToSFCGAL(OGRGeometry *poGeom);
     30static OGRGeometry* SFCGALexportToOGR(sfcgal_geometry_t* _geometry);
     31}}}
     32Besides SFCGAL, GEOS methods are still used in some cases, but with the following limitations - a Triangle is converted to a Polygon with one exterior ring; Polyhedral Surfaces and Triangulated Surfaces are converted to MultiPolygons. (each Triangle in a Triangulated Surface is converted to a Polygon as described previously) [[BR]]
     33[[BR]]
     34The API for the new geometries introduced includes - [[BR]]
     35* Overwriting existing methods for Polygon in the case of Triangle API. A complete API is provided below - [[BR]]
     36{{{
     37class CPL_DLL OGRTriangle : public OGRPolygon
     38{
     39  public:
     40    OGRTriangle();
     41    OGRTriangle(const OGRPoint &p, const OGRPoint &q, const OGRPoint &r);
     42    OGRTriangle(const OGRTriangle &other);
     43    OGRTriangle& operator=(const OGRTriangle& other);
     44    virtual ~OGRTriangle();
     45    const char *getGeometryName() const;
     46    virtual OGRwkbGeometryType getGeometryType() const;
     47
     48    // IWks Interface
     49    virtual int WkbSize() const;
     50    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
     51    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
     52    virtual OGRErr importFromWkt( char ** );
     53    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
     54
     55    // New methods interfaced through SFCGAL or rewritten from OGRPolygon/OGRCurvePolygon/OGRGeometry
     56    virtual OGRGeometry *Boundary() const CPL_WARN_UNUSED_RESULT;
     57    virtual double Distance3D(const OGRGeometry *poOtherGeom) const;
     58    virtual OGRErr       Centroid( OGRPoint * poPoint ) const;
     59    virtual OGRBoolean  IsSimple() const;
     60    virtual OGRBoolean  IsRing() const;
     61    virtual OGRErr addRing  (OGRCurve *poNewRing);
     62    virtual OGRErr      PointOnSurface( OGRPoint * poPoint ) const;
     63    virtual OGRGeometry *Polygonize() const CPL_WARN_UNUSED_RESULT;
     64    virtual OGRGeometry *SymDifference( const OGRGeometry *poOtherGeom) const CPL_WARN_UNUSED_RESULT;
     65    virtual OGRBoolean  Touches( const OGRGeometry * ) const;
     66    virtual double      get_Area() const;
     67};
     68}}}
     69* The PolyhedralSurface API is derived from OGRSurface. Internally, it uses an OGRMultiPolygon to store all the Polygons comprising the Polyhedral Surface. Most of the implementations of the methods just reference corresponding OGRMultiPolygon methods with checks to ensure that conditions are maintained.
     70{{{
     71class CPL_DLL OGRPolyhedralSurface : public OGRSurface
     72{
     73  protected:
     74    OGRMultiPolygon oMP;
     75    virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon() const;
     76    virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon() const;
     77    OGRErr exportToWktInternal (char ** ppszDstText, OGRwkbVariant eWkbVariant, const char* pszSkipPrefix ) const;
     78
     79  public:
     80    OGRPolyhedralSurface();
     81    OGRPolyhedralSurface(const OGRPolyhedralSurface &poGeom);
     82    virtual ~OGRPolyhedralSurface();
     83    OGRPolyhedralSurface& operator=(const OGRPolyhedralSurface& other);
     84
     85    // IWks Interface
     86    virtual int WkbSize() const;
     87    virtual const char *getGeometryName() const;
     88    virtual OGRwkbGeometryType getGeometryType() const;
     89    virtual OGRErr importFromWkb( unsigned char *, int=-1, OGRwkbVariant=wkbVariantOldOgc );
     90    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
     91    virtual OGRErr importFromWkt( char ** );
     92    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
     93
     94    // IGeometry methods
     95    virtual int getDimension() const;
     96
     97    virtual void empty();
     98
     99    virtual OGRGeometry *clone() const;
     100    virtual void getEnvelope(OGREnvelope * psEnvelope) const;
     101    virtual void getEnvelope(OGREnvelope3D * psEnvelope) const;
     102
     103    virtual void flattenTo2D();
     104    virtual OGRErr transform(OGRCoordinateTransformation*);
     105    virtual OGRBoolean Equals(OGRGeometry*) const;
     106    virtual double get_Area() const;
     107    virtual OGRErr PointOnSurface(OGRPoint*) const;
     108
     109    OGRMultiPolygon* CastToMultiPolygon();
     110    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
     111    virtual OGRErr addGeometry( const OGRGeometry * );
     112    virtual OGRErr addGeometryDirectly(OGRGeometry *poNewGeom);
     113    virtual int getNumGeometries();
     114    virtual OGRGeometry* getGeometry(int i);
     115
     116    virtual OGRBoolean  IsEmpty() const;
     117    virtual void setCoordinateDimension( int nDimension );
     118    virtual void set3D( OGRBoolean bIs3D );
     119    virtual void setMeasured( OGRBoolean bIsMeasured );
     120    virtual void swapXY();
     121    virtual double Distance3D(const OGRGeometry *poOtherGeom) const;
     122    virtual OGRErr removeGeometry( int iIndex, int bDelete = TRUE );
     123};
     124}}}
     125* The Triangulated Surface API is similar to Polyhedral Surface, and the MultiPolygon class was tweaked slightly to include methods to run which consisted of subgeometries of the form Triangle. (A MultiPolygon is strictly a collection of Polygons). These methods are internal to OGRMultiPolygon and cannot be accessed by a public user. For instance, the `OGRMultiPolygon::addGeomtryDirectly` method has a check that the subgeometry added to it should be of the type POLYGON. Rather than mess around with the existing function, a new function has been written which does not implement this check -
     126{{{
     127/************************************************************************/
     128/*                         _addGeometryDirectly()                       */
     129/*      Only to be used in conjunction with OGRTriangulatedSurface.     */
     130/*                        DO NOT USE IT ELSEWHERE.                      */
     131/************************************************************************/
     132
     133OGRErr OGRMultiPolygon::_addGeometryDirectly( OGRGeometry * poNewGeom )
     134{
     135    if ( wkbFlatten(poNewGeom->getGeometryType()) != wkbTriangle)
     136        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     137
     138    if( poNewGeom->Is3D() && !Is3D() )
     139        set3D(TRUE);
     140
     141    if( poNewGeom->IsMeasured() && !IsMeasured() )
     142        setMeasured(TRUE);
     143
     144    if( !poNewGeom->Is3D() && Is3D() )
     145        poNewGeom->set3D(TRUE);
     146
     147    if( !poNewGeom->IsMeasured() && IsMeasured() )
     148        poNewGeom->setMeasured(TRUE);
     149
     150    OGRGeometry** papoNewGeoms = (OGRGeometry **) VSI_REALLOC_VERBOSE( papoGeoms,
     151                                             sizeof(void*) * (nGeomCount+1) );
     152    if( papoNewGeoms == NULL )
     153        return OGRERR_FAILURE;
     154
     155    papoGeoms = papoNewGeoms;
     156    papoGeoms[nGeomCount] = poNewGeom;
     157    nGeomCount++;
     158
     159    return OGRERR_NONE;
     160}
     161}}}
     162* The Triangulated Surface API is as follows - [[BR]]
     163{{{
     164class CPL_DLL OGRTriangulatedSurface : public OGRPolyhedralSurface
     165{
     166  public:
     167    OGRTriangulatedSurface();
     168    OGRTriangulatedSurface(const OGRTriangulatedSurface &other);
     169    ~OGRTriangulatedSurface();
     170
     171    OGRTriangulatedSurface& operator=(const OGRTriangulatedSurface& other);
     172    virtual const char *getGeometryName() const;
     173    virtual OGRwkbGeometryType getGeometryType() const;
     174
     175    // IWks Interface
     176    virtual int WkbSize() const;
     177    virtual OGRErr importFromWkb(unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc);
     178    virtual OGRErr exportToWkb(OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc) const;
     179    virtual OGRErr importFromWkt(char **);
     180    virtual OGRErr exportToWkt(char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc) const;
     181
     182    virtual OGRGeometry *clone() const;
     183    virtual OGRErr addGeometry( const OGRGeometry * );
     184    virtual OGRErr addGeometryDirectly(OGRGeometry *poNewGeom);
     185    OGRMultiPolygon* CastToMultiPolygon();
     186};
     187}}}
     188
     189== Geometry types ==
     190The new geometry WKB values can be seen as below - [[BR]]
     191[[BR]]
     192|| Geometry Type        ||   2D ||    Z ||    M ||   ZM ||
     193|| PolyhedralSurface    || 0015 || 1015 || 2015 || 3015 ||
     194|| TIN                  || 0016 || 1016 || 2016 || 3016 ||
     195|| Triangle             || 0017 || 1017 || 2017 || 3017 ||
     196[[BR]]
     197== Changes in drivers ==
     198Some drivers were modified to be compatible with the new geometries. These include -> [[BR]]
     199
     200* PostGIS - No changes done to the driver explicitly, but it has been ensured that PG <-> OGR compatibility has been maintained. PostGIS 3D functions work on OGR, simple scripts work, for example from `autotest/ogr/ogr_pg.py`, we have -
     201{{{
     202wkt_list = ['POLYHEDRALSURFACE (((0 0 0,0 0 1,0 1 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,1 0 1,0 0 1,0 0 0)),((1 1 0,1 1 1,1 0 1,1 0 0,1 1 0)),((0 1 0,0 1 1,1 1 1,1 1 0,0 1 0)),((0 0 1,1 0 1,1 1 1,0 1 1,0 0 1)))',
     203                'TIN (((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 1 0,0 0 0)))',
     204                'TRIANGLE ((48 36 84,32 54 64,86 11 54,48 36 84))' ]
     205
     206for i in range(0,3):
     207        gdaltest.pg_ds.ExecuteSQL( "INSERT INTO zgeoms (field_no, wkb_geometry) VALUES (%d,GeomFromEWKT('%s'))" % ( i, wkt_list[i] ) )
     208}}}
     209
     210* ShapeFile - TriangleStrip and TriangleFan objects in ShapeFile are parsed to OGRTriangulatedSurface. According to ESRI specs,
     211 * A TriangleStrip is a linked strip of triangles, where every vertex (after the first two) completes a new triangle. A new triangle is always formed by connecting the new vertex with its two immediate predecessors.
     212 * A TriangleFan is a linked fan of triangles, where every vertex (after the first two) completes a new triangle. A new triangle is always formed by connecting the new vertex with its immediate predecessor and the first vertex of the part.
     213 * Two different OGRTriangulatedSurface are maintained for each TriStrip and TriFan. If both are present in the file read, then an OGRGeometryCollection object is the result which consists of both OGRTriangulatedSurface which correspond to TriStrip and TriFan. (This is not strictly legal, since a TriangulatedSurface should not be a subgeometry of GeometryCollection)
     214* GML - GML has been modified for both input and output -> Triangle, PolyhedralSurface and TriangulatedSurface are capable of being read/written from/to a GML document. Sample examples include -
     215{{{
     216'TRIANGLE ((0 0,0 1,0 1,0 0))' is parsed to -
     217'<gml:Triangle>
     218    <gml:exterior>
     219        <gml:LinearRing>
     220            <gml:posList>0 0 0 1 0 1 0 0</gml:posList>
     221        </gml:LinearRing>
     222    </gml:exterior>
     223</gml:Triangle>'
     224
     225<gml:PolyhedralSurface>
     226   <gml:polygonPatches>
     227       <gml:PolygonPatch>
     228           <gml:exterior>
     229               <gml:LinearRing>
     230                   <gml:posList srsDimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList>
     231               </gml:LinearRing>
     232           </gml:exterior>
     233       </gml:PolygonPatch>
     234       <gml:PolygonPatch>
     235           <gml:exterior>
     236               <gml:LinearRing>
     237                   <gml:posList srsDimension="3">10 11 12 13 14 15 16 17 18 10 11 12</gml:posList>
     238               </gml:LinearRing>
     239           </gml:exterior>
     240           <gml:interior>
     241               <gml:LinearRing>
     242                   <gml:posList srsDimension="3">19 20 21 22 23 24 25 26 27 19 20 21</gml:posList>
     243               </gml:LinearRing>
     244           </gml:interior>
     245       </gml:PolygonPatch>
     246   </gml:polygonPatches>
     247</gml:PolyhedralSurface>"""
     248
     249gets parsed to 'POLYHEDRALSURFACE Z (((1 2 3,4 5 6,7 8 9,1 2 3)),((10 11 12,13 14 15,16 17 18,10 11 12),(19 20 21,22 23 24,25 26 27,19 20 21)))'
     250
     251Each PolygonPatch/Patch corresponds to one Polygon in a PolyhedralSurface.
     252
     253Finally, 'POLYHEDRALSURFACE EMPTY' parses to
     254'<gml:PolyhedralSurface>
     255    <gml:polygonPatches>
     256    </gml:polygonPatches>
     257</gml:PolyhedralSurface>'
     258}}}
     259* DXF changes include converting a PolyFaceMesh (a subtype of PolyLine) to PolyhedralSurface. This is illustrated by a bug on the GDAL trac - https://trac.osgeo.org/gdal/ticket/6246. A PolyFace Mesh consists of points defined initially using specific codes, then these points are described as part of a polygon (a polygon can have four points at the maximum). Reading the PolyFace Mesh is supported in OGR as of now, but write support for it as well (though not implemented by me in this changeset) should be possible as well now.
     260
     261== Documentation ==
     262Using standard Doxygen documentation procedure.
     263
     264== Testing ==
     265Rigorous testing of all the use cases I can think of. Please feel free to add your own test to the autotest suite to check the stability of the code.
     266
     267== Implementation ==
     268Done by Avyav Kumar Singh, under the Google Summer of Code 2016 program.