Oracle Spatial中SDO_Geometry详细说明


Oracle中SDO_GEOMETRY数据类型是一个很有威力的结构。你可以用这个类型存储点、线串、多边形、面和立方体等几何体,同样还可以存储这些几何体的同构或异构集合。SDO_GEOMETRY中的SDO_GTYPE属性指定几何体类型(形状),SDO_ELEM_INFO属性和SDO_ORDINATES属性一起指定了几何体的坐标信息和连通性。SDO_POINT属性存储二维或三维的点的位置。简而言之,你可以将OGC简单特性规范12中提到的任何二维类型以及OGC GML 2.0和3.0规范中提到的大多数三维类型(不包括参数曲线和参数面)存储为一个SDO_GEOMETRY。
除了几何结构外,你可以用合适的坐标系将空间参照和SDO_GEOMETRY对象相关联。如果坐标系是基于EPSG模型的,你可以在不同坐标系之间定义自己的转换路径。

SDO_GEOMETRY类型、属性和值

这里写图片描述

下面是SDO_GEOMETRY每个属性的用处:
SDO_GTYPE属性,表示几何体实际形状的类型(点、线串、多边形、集合、多重点、多重线串或者多重多边形)。尽管SDO_GTYPE属性表示几何体的类型,但它并不指定实际的坐标。
SDO_SRID属性,指定空间参考系(坐标系)的ID。几何体的位置和形状都在该参考系中确定。
如果几何体是一个点(如客户的位置),你可以把它的坐标存储到SDO_GEOMETRY的SDO_POINT属性中。
如果几何体是一个任意形状(如街区网络或城市边界),则可以把它的坐标存储到SDO_ORDINATES和SDO_ELEM_INFO数组属性:
SDO_ORDINATES属性存储所有几何体元素的坐标。
SDO_ELEM_INFO规定在SDO_ORDINATES数组中,一个新的元素从什么地方开始,怎么连接(通过直线还是弧),是点(推荐用SDO_POINT来存储和表示点,)、线串还是多边形。
下面进一步介绍这些属性。

SDO_GTYPE属性

SDO_GTYPE是一个4位的数字,结构为D00T。第一位和最后一位根据几何体的维数和形状采用不同的值,如表4-1所示。第二位和第三位通常被设成0。
这里写图片描述
下面就是D=2的二维几何类型,SDO_GTYPE参数值具体,如图:
这里写图片描述
对于一个给定的层,所有的地理对象必须都是相同的维度,不能将二维与三维的数据放在一个层里。
Oracle默认为二维的数据图层,若表示三维的数据图层,需向USER_SDO_GEOM_METADATA的DIMINFO插入X、Y、Z空间索引范围。
这里写图片描述

SDO_SRID属性

SDO_SRID定义了空间坐标参考系统。如果SDO_SRID为null,则没有指定坐标系统,如果SDO_SRID不为null,那么它的值必须在在MDSYS.CS_SRS 表中的 SRID 列有对应的值,而且它的值必须插入USER_SDO_GEOM_METADATA视图中。
查询srid
这里写图片描述
具体描述信息
这里写图片描述

SDO_POINT属性

SDO_POINT_TYPE数据类型:
这里写图片描述
SDO_GTYPE:格式是D00T,对二维点来说D为2,T为1。
SDO_SRID:它被设置为8307。
SDO_POINT:这个例子中的x,y坐标被设置为SDO_POINT_TYPE类型(-79,37)。z轴为NULL。
SDO_ELEM_INFO:没有被使用,设为NULL。
SDO_ORDINATES:没有被使用,设为NULL。
构造为:SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(79, 37, NULL), NULL, NULL)

SDO_ELEM_INFO属性

SDO_ELEM_INFO类型的构造方法为:sdo_elem_info_array(a,b.c),其中a,b.c为Number类型。

SDO_ELEM_INFO是理解和掌握SDO_Geometry的重点和难点,SDO_ELEM_INFO 定义了如何理解SDO_ORDINATES中的坐标字符串属性。

SDO_ELEM_INFO每三个数字组合为一个SDO_ELEM_INFO属性单元(具体可以结合下面的例子理解)。

每个SDO_ELEM_INFO属性单元由:SDO_STARTING_OFFSET、SDO_ETYPE 和SDO_INTERPRETATION 组成。下面介绍一下这三个数字的具体含义:

SDO_STARTING_OFFSET:声明了组成当前几何片段的第一个坐标在SDO_ORDINATES数组中的坐标序号。坐标序号是从1开始起算的而非从0开始。这里的SDO_ORDINATES就是sdo_geometry 中的坐标序列,坐标序列是已逗号隔开的数字,具体的计算如:sdo_ordinate_array(1,4,6,7,8,9)中如果以’6’开始几何片段的话,坐标序号SDO_STARTING_OFFSET=3。(具体参考下面的例子理解)
SDO_ETYPE :声明元素的类型。可结合 SDO_STARTING_OFFSET和SDO_ETYPE 表来理解.

SDO_ETYPE 值 = 1, 2, 1003,或2003,说明几何为简单的几何类型。可以全部按SDO_ELEM_INFO 属性单元【即三个以逗号隔开的数】来理解sdo_ordinate_array中的坐标序列。

特别说明:SDO_ETYPE 值 = 1003 ,假如几何类型为面,则表示为外多边形环(以逆时针顺序)

SDO_ETYPE 值 = 2003 ,假如几何类型为面,则表示为内多边形环(以顺时针顺序)

SDO_ETYPE 值 = 4,1005或2005,说明几何为组合元素,往往第一个三数字组不是SDO_ELEM_INFO 属性单元,而是为了说明组合元素的信息。具体可以参见下面 复杂多义线 和 复杂多边形 的例子。

SDO_INTERPRETATION:有两种可能的意思,依赖地SDO_ETYPE是否是组合元素。如果SDO_ETYPE 值 = 4,1005或2005,标识的是有多少组合部分,具体参考 复杂多义线 和 复杂多边形 的例子。如果SDO_ETYPE 值 = 1, 2, 1003,或2003,标识决定了元素坐标队列的翻译顺序。

SDO_STARTING_OFFSET和SDO_ETYPE 表 如下图:
这里写图片描述

SDO_ORDINATES属性

SDO_ORDINATES类型的构造方法为:sdo_ordinate_array(x1,y1,x2,y2,……),其中x1,y1类型等为Double和Int都可。

SDO_ORDINATES存储的是空间对象的几何节点坐标序列,用逗号将X、Y、Z以及不同点之间隔开,该字段性质:长度=1048576的数字Number类型。如果几何为二维的情况,存储的序列为{Y1, X2, Y2, X3, Y3, X4, Y4……}格式;几何为三维坐标的话,如三维坐标的多边形它的存储的序列为{X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, X4, Y4, Z4, X1, Y1, Z1}格式。坐标序列中的数据必须都合法且不为空。具体坐标的组合成几何的结合SDO_ELEM_INFO来理解。

例子

这里写图片描述
该几何体的构造函数如下所示:

SDO_GEOMETRY  
(  
    2002,32774,null,  
    SDO_ELEM_INFO_ARRAY(1,2,2),  
    SDO_ORDINATE_ARRAY(Xa,Ya, Xb,Yb, Xc,Yc, Xd,Yd, Xe,Ye)  
) 

这里写图片描述
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述
SQL> INSERT INTO geometry_examples (name, description, geom) VALUES
(
‘3-D Composite Surface’,
‘3-dimensional Composite with 2 rectangle polygons ‘,
SDO_GEOMETRY
(
3003, – SDO_GTYPE format: D00T. Set to
3003 for a 3-dimensional Surface
NULL, – No coordinate system
NULL, – No data in SDO_POINT attribute
SDO_ELEM_INFO_ARRAY(
1, – Offset of composite element
1006, – Etype for composite surface element
2, – Number of composing polygons
1, – Offset for ordinates in SDO_ORDINATE_ARRAY
1003, – Etype for Exterior (outer) ring of FIRST polygon
3, – Polygon is an axis-aligned rectangle
7, – Offset for second exterior polygon
1003, – Etype for exterior Ring of SECOND polygon
3 – Polygon is an axis-aligned rectangle
),
SDO_ORDINATE_ARRAY
(
2, 0,2, – min-corner for exterior ring of first polygon,
4,2,2, – max-corner for exterior ring of first polygon
2,0, 2, – min-corner for second element rectangle
4,0,4 – max-corner for second element rectangle
)
)
);
立方体下一步解释。

附:自己整理了sdogeometry与gdal对象互相转换(c++代码)

//sdogeometry ->OGRGeometry
SS_CLASS_EXPORT OGRGeometry* TranslateGeometry( SSDataBase::SSDBSDOGeometry* pSdoGeometry );
//OGRGeometry ->SDOGeometry
SS_CLASS_EXPORT SSDataBase::SSDBSDOGeometry* TranslateToSDOGeometry( OGRGeometry * poGeometry, int *pnGType );

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool OGROCIStrokeArcToOGRGeometry_Angles( double dfCenterX, double dfCenterY,
double dfRadius,
double dfStartAngle, double dfEndAngle,
double dfMaxAngleStepSizeDegrees,
OGRLineString *poLine )

{
double dfArcX, dfArcY, dfSlice;
int iPoint, iAppendLocation, nVertexCount;
double dfEps = dfRadius / 100000.0;

nVertexCount = (int) 
    ceil(fabs(dfEndAngle - dfStartAngle)/dfMaxAngleStepSizeDegrees) + 1;
nVertexCount = MAX(2,nVertexCount);
dfSlice = (dfEndAngle-dfStartAngle)/(nVertexCount-1);

for( iPoint=0; iPoint < nVertexCount; iPoint++ )
{
    double      dfAngle;

    dfAngle = (dfStartAngle + iPoint * dfSlice) * PI / 180.0;

    dfArcX = dfCenterX + cos(dfAngle) * dfRadius;
    dfArcY = dfCenterY + sin(dfAngle) * dfRadius;

    if( iPoint == 0 )
    {
        iAppendLocation = poLine->getNumPoints();

        if( poLine->getNumPoints() > 0 
            && fabs(poLine->getX(poLine->getNumPoints()-1)-dfArcX) < dfEps
            && fabs(poLine->getY(poLine->getNumPoints()-1)-dfArcY) < dfEps)
        {
            poLine->setNumPoints( 
                poLine->getNumPoints() + nVertexCount - 1 );
        }
        else
        {
            poLine->setNumPoints( 
                poLine->getNumPoints() + nVertexCount - 1 );
            poLine->setPoint( iAppendLocation++, dfArcX, dfArcY );
        }
    }
    else
        poLine->setPoint( iAppendLocation++, dfArcX, dfArcY );
}

return true;

}

bool OGROCIArcCenterFromEdgePoints( double x_c0, double y_c0,
double x_c1, double y_c1,
double x_c2, double y_c2,
double *x_center, double *y_center )

{

/* -------------------------------------------------------------------- */
/*      Handle a degenerate case that occurs in OSNI products by        */
/*      making some assumptions.  If the first and third points are     */
/*      the same assume they are intended to define a full circle,      */
/*      and that the second point is on the opposite side of the        */
/*      circle.                                                         */
/* -------------------------------------------------------------------- */
if( x_c0 == x_c2 && y_c0 == y_c2 )
{
    *x_center = (x_c0 + x_c1) * 0.5;
    *y_center = (y_c0 + y_c1) * 0.5;

    return true;
}

/* -------------------------------------------------------------------- */
/*      Compute the inverse of the slopes connecting the first and      */
/*      second points.  Also compute the center point of the two        */
/*      lines ... the point our crossing line will go through.          */
/* -------------------------------------------------------------------- */
double m1, x1, y1;

if( (y_c1 - y_c0) != 0.0 )
    m1 = (x_c0 - x_c1) / (y_c1 - y_c0);
else
    m1 = 1e+10;

x1 = (x_c0 + x_c1) * 0.5;
y1 = (y_c0 + y_c1) * 0.5;

/* -------------------------------------------------------------------- */
/*      Compute the same for the second point compared to the third     */
/*      point.                                                          */
/* -------------------------------------------------------------------- */
double m2, x2, y2;

if( (y_c2 - y_c1) != 0.0 )
    m2 = (x_c1 - x_c2) / (y_c2 - y_c1);
else
    m2 = 1e+10;

x2 = (x_c1 + x_c2) * 0.5;
y2 = (y_c1 + y_c2) * 0.5;

/* -------------------------------------------------------------------- */
/*      Turn these into the Ax+By+C = 0 form of the lines.              */
/* -------------------------------------------------------------------- */
double      a1, a2, b1, b2, c1, c2;

a1 = m1;
a2 = m2;

b1 = -1.0;
b2 = -1.0;

c1 = (y1 - m1*x1);
c2 = (y2 - m2*x2);

/* -------------------------------------------------------------------- */
/*      Compute the intersection of the two lines through the center    */
/*      of the circle, using Kramers rule.                              */
/* -------------------------------------------------------------------- */
double      det_inv;

if( a1*b2 - a2*b1 == 0.0 )
    return false;

det_inv = 1 / (a1*b2 - a2*b1);

*x_center = (b1*c2 - b2*c1) * det_inv;
*y_center = (a2*c1 - a1*c2) * det_inv;

return true;

}

bool OGROCIStrokeArcToOGRGeometry_Points( double dfStartX, double dfStartY,
double dfAlongX, double dfAlongY,
double dfEndX, double dfEndY,
double dfMaxAngleStepSizeDegrees,
int bForceWholeCircle,
OGRLineString *poLine )

{
double dfStartAngle, dfEndAngle, dfAlongAngle;
double dfCenterX, dfCenterY, dfRadius;

if( !OGROCIArcCenterFromEdgePoints( dfStartX, dfStartY, 
    dfAlongX, dfAlongY,
    dfEndX, dfEndY, 
    &dfCenterX, &dfCenterY ) )
    return false;

if( bForceWholeCircle || (dfStartX == dfEndX && dfStartY == dfEndY) )
{
    dfStartAngle = 0.0;
    dfEndAngle = 360.0;
}
else
{
    double  dfDeltaX, dfDeltaY;

    dfDeltaX = dfStartX - dfCenterX;
    dfDeltaY = dfStartY - dfCenterY;
    dfStartAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;

    dfDeltaX = dfAlongX - dfCenterX;
    dfDeltaY = dfAlongY - dfCenterY;
    dfAlongAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;

    dfDeltaX = dfEndX - dfCenterX;
    dfDeltaY = dfEndY - dfCenterY;
    dfEndAngle = atan2(dfDeltaY,dfDeltaX) * 180.0 / PI;

    // Try positive (clockwise?) winding.
    while( dfAlongAngle < dfStartAngle )
        dfAlongAngle += 360.0;

    while( dfEndAngle < dfAlongAngle )
        dfEndAngle += 360.0;

    // If that doesn't work out, then go anticlockwise.
    if( dfEndAngle - dfStartAngle > 360.0 )
    {
        while( dfAlongAngle > dfStartAngle )
            dfAlongAngle -= 360.0;

        while( dfEndAngle > dfAlongAngle )
            dfEndAngle -= 360.0;
    }
}

dfRadius = sqrt( (dfCenterX - dfStartX) * (dfCenterX - dfStartX)
    + (dfCenterY - dfStartY) * (dfCenterY - dfStartY) );

bool bResult;

bResult = 
    OGROCIStrokeArcToOGRGeometry_Angles( dfCenterX, dfCenterY, 
    dfRadius, 
    dfStartAngle, dfEndAngle,
    dfMaxAngleStepSizeDegrees,
    poLine );

/* -------------------------------------------------------------------- */
/*      Force the points for arcs, to avoid odd rounding/math           */
/*      issues.  Perhaps we should do this for the start too, but       */
/*      this is a bit tricky since it isn't obvious which point is      */
/*      the start.                                                      */
/* -------------------------------------------------------------------- */
if( bResult && !bForceWholeCircle )
{
    poLine->setPoint( poLine->getNumPoints() - 1, 
        dfEndX, dfEndY );
}

return bResult;

}

//获取点列坐标
bool GetOrdinalPoint( int iOrdinal, int nDimension,double pdfX, double *pdfY, double *pdfZ, SSDataBase::SSGeomData pSSGeomData )
{
*pdfX = pSSGeomData->GetOrdinates()->at( iOrdinal );
*pdfY = pSSGeomData->GetOrdinates()->at( iOrdinal + 1);
if( nDimension == 3 )
*pdfZ = pSSGeomData->GetOrdinates()->at( iOrdinal + 2 );

return true;

}

//根据elementinfo转换到Geometry
OGRGeometry * TranslateGeometryElement( int *piElement, int nGType, int nDimension,int nEType, int nInterpretation,
int nStartOrdinal, int nElemOrdCount, SSDataBase::SSGeomData* pSSGeomData )

{
/* ——————————————————————– */
/* Handle simple point. */
/* ——————————————————————– */
if( nEType == 1 && nInterpretation == 1 )
{
OGRPoint *poPoint = new OGRPoint();
double dfX, dfY, dfZ = 0.0;

    GetOrdinalPoint( nStartOrdinal, nDimension, &dfX, &dfY, &dfZ, pSSGeomData );

    poPoint->setX( dfX );
    poPoint->setY( dfY );
    if( nDimension == 3 )
        poPoint->setZ( dfZ );

    return poPoint;
}

/* -------------------------------------------------------------------- */
/*      Handle multipoint.                                              */
/* -------------------------------------------------------------------- */
else if( nEType == 1 && nInterpretation > 1 )
{
    OGRMultiPoint *poMP = new OGRMultiPoint();
    double dfX, dfY, dfZ = 0.0;
    int i;

    assert( nInterpretation == nElemOrdCount / nDimension );

    for( i = 0; i < nInterpretation; i++ )
    {
        GetOrdinalPoint( nStartOrdinal + i*nDimension, nDimension, 
            &dfX, &dfY, &dfZ, pSSGeomData );

        OGRPoint *poPoint = (nDimension == 3) ? new OGRPoint( dfX, dfY, dfZ ):  new OGRPoint( dfX, dfY );
        poMP->addGeometryDirectly( poPoint );
    }
    return poMP;
}

/* -------------------------------------------------------------------- */
/*      Discard orientations for oriented points.                       */
/* -------------------------------------------------------------------- */
else if( nEType == 1 && nInterpretation == 0 )
{
    return NULL;
}

/* -------------------------------------------------------------------- */
/*      Handle line strings consisting of straight segments.            */
/* -------------------------------------------------------------------- */
else if( nEType == 2 && nInterpretation == 1 )
{
    OGRLineString *poLS = new OGRLineString();
    int nPointCount = nElemOrdCount / nDimension, i;

    poLS->setNumPoints( nPointCount );

    for( i = 0; i < nPointCount; i++ )
    {
        double dfX, dfY, dfZ = 0.0;

        GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension, 
            &dfX, &dfY, &dfZ, pSSGeomData );
        if (nDimension == 3)
            poLS->setPoint( i, dfX, dfY, dfZ );
        else
            poLS->setPoint( i, dfX, dfY );
    }

    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Handle line strings consisting of circular arcs.                */
/* -------------------------------------------------------------------- */
else if( nEType == 2 && nInterpretation == 2 )
{
    OGRLineString *poLS = new OGRLineString();
    int nPointCount = nElemOrdCount / nDimension, i;

    for( i = 0; i < nPointCount-2; i += 2 )
    {
        double dfStartX, dfStartY, dfStartZ = 0.0; 
        double dfMidX, dfMidY, dfMidZ = 0.0;
        double dfEndX, dfEndY, dfEndZ = 0.0; 

        GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension, 
            &dfStartX, &dfStartY, &dfStartZ, pSSGeomData );
        GetOrdinalPoint( (i+1)*nDimension + nStartOrdinal, nDimension, 
            &dfMidX, &dfMidY, &dfMidZ, pSSGeomData  );
        GetOrdinalPoint( (i+2)*nDimension + nStartOrdinal, nDimension, 
            &dfEndX, &dfEndY, &dfEndZ, pSSGeomData  );

        OGROCIStrokeArcToOGRGeometry_Points( dfStartX, dfStartY, 
            dfMidX, dfMidY,
            dfEndX, dfEndY,
            6.0, FALSE, poLS );
    }

    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Handle polygon rings.  Treat curves as if they were             */
/*      linestrings.                                                    */
/* -------------------------------------------------------------------- */
else if( nEType % 1000 == 3 && nInterpretation == 1 )
{
    OGRLinearRing *poLS = new OGRLinearRing();
    int nPointCount = nElemOrdCount / nDimension, i;

    poLS->setNumPoints( nPointCount );

    for( i = 0; i < nPointCount; i++ )
    {
        double dfX, dfY, dfZ = 0.0;

        GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension, 
            &dfX, &dfY, &dfZ, pSSGeomData );
        if (nDimension == 3)
            poLS->setPoint( i, dfX, dfY, dfZ );
        else
            poLS->setPoint( i, dfX, dfY );
    }

    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Handle polygon rings made of circular arcs.                     */
/* -------------------------------------------------------------------- */
else if( nEType % 1000 == 3 && nInterpretation == 2 )
{
    OGRLineString *poLS = new OGRLinearRing();
    int nPointCount = nElemOrdCount / nDimension, i;

    for( i = 0; i < nPointCount-2; i += 2 )
    {
        double dfStartX, dfStartY, dfStartZ = 0.0; 
        double dfMidX, dfMidY, dfMidZ = 0.0;
        double dfEndX, dfEndY, dfEndZ = 0.0; 

        GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension, 
            &dfStartX, &dfStartY, &dfStartZ, pSSGeomData );
        GetOrdinalPoint( (i+1)*nDimension + nStartOrdinal, nDimension, 
            &dfMidX, &dfMidY, &dfMidZ, pSSGeomData );
        GetOrdinalPoint( (i+2)*nDimension + nStartOrdinal, nDimension, 
            &dfEndX, &dfEndY, &dfEndZ, pSSGeomData );

        OGROCIStrokeArcToOGRGeometry_Points( dfStartX, dfStartY, 
            dfMidX, dfMidY,
            dfEndX, dfEndY,
            6.0, FALSE, poLS );
    }

    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Handle rectangle definitions ... translate into a linear ring.  */
/* -------------------------------------------------------------------- */
else if( nEType % 1000 == 3 && nInterpretation == 3 )
{
    OGRLinearRing *poLS = new OGRLinearRing();
    double dfX1, dfY1, dfZ1 = 0.0;
    double dfX2, dfY2, dfZ2 = 0.0;

    GetOrdinalPoint( nStartOrdinal, nDimension, 
        &dfX1, &dfY1, &dfZ1, pSSGeomData );
    GetOrdinalPoint( nStartOrdinal + nDimension, nDimension, 
        &dfX2, &dfY2, &dfZ2, pSSGeomData );

    poLS->setNumPoints( 5 );

    poLS->setPoint( 0, dfX1, dfY1, dfZ1 );
    poLS->setPoint( 1, dfX2, dfY1, dfZ1 );
    poLS->setPoint( 2, dfX2, dfY2, dfZ2 );
    poLS->setPoint( 3, dfX1, dfY2, dfZ2 );
    poLS->setPoint( 4, dfX1, dfY1, dfZ1 );

    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Handle circle definitions ... translate into a linear ring.     */
/* -------------------------------------------------------------------- */
else if( nEType % 100 == 3 && nInterpretation == 4 )
{
    OGRLinearRing *poLS = new OGRLinearRing();
    double dfX1, dfY1, dfZ1 = 0.0;
    double dfX2, dfY2, dfZ2 = 0.0;
    double dfX3, dfY3, dfZ3 = 0.0;

    GetOrdinalPoint( nStartOrdinal, nDimension, 
        &dfX1, &dfY1, &dfZ1, pSSGeomData );
    GetOrdinalPoint( nStartOrdinal + nDimension, nDimension, 
        &dfX2, &dfY2, &dfZ2, pSSGeomData );
    GetOrdinalPoint( nStartOrdinal + nDimension*2, nDimension, 
        &dfX3, &dfY3, &dfZ3, pSSGeomData );

    OGROCIStrokeArcToOGRGeometry_Points( dfX1, dfY1, 
        dfX2, dfY2,
        dfX3, dfY3, 
        6.0, TRUE, poLS );

    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Handle compound line strings and polygon rings.                 */
/*                                                                      */
/*      This is quite complicated since we need to consume several      */
/*      following elements, and merge the resulting geometries.         */
/* -------------------------------------------------------------------- */
else if( nEType == 4  || nEType % 100 == 5 )
{
    int nSubElementCount = nInterpretation;
    OGRLineString *poLS, *poElemLS;
    int nElemCount, nTotalOrdCount;

    if( nEType == 4 )
        poLS = new OGRLineString();
    else 
        poLS = new OGRLinearRing();

    nElemCount = pSSGeomData->GetElemInfo()->size();
    nTotalOrdCount = pSSGeomData->GetOrdinates()->size();

    for( *piElement += 3; nSubElementCount-- > 0;  *piElement += 3 )
    {

        //loadelementinfo
        nStartOrdinal = pSSGeomData->GetElemInfo()->at( *piElement );
        nEType = pSSGeomData->GetElemInfo()->at( *piElement + 1);
        nInterpretation = pSSGeomData->GetElemInfo()->at( *piElement + 2 );


        if( *piElement < nElemCount-3 )
        {
            int nNextStartOrdinal = pSSGeomData->GetElemInfo()->at( *piElement + 3);
            nElemOrdCount = nNextStartOrdinal - nStartOrdinal;
        }
        else
            nElemOrdCount = nTotalOrdCount - nStartOrdinal + 1;


        // Adjust for repeated end point except for last element.
        if( nSubElementCount > 0 )
            nElemOrdCount += nDimension;

        // translate element.
        poElemLS = (OGRLineString *)
            TranslateGeometryElement( piElement, nGType, nDimension, 
            nEType, nInterpretation,
            nStartOrdinal - 1, nElemOrdCount, pSSGeomData );

        // Try to append to our aggregate linestring/ring
        if( poElemLS )
        {
            if( poLS->getNumPoints() > 0 )
            {
                assert( 
                    poElemLS->getX(0) == poLS->getX(poLS->getNumPoints()-1)
                    && poElemLS->getY(0) ==poLS->getY(poLS->getNumPoints()-1));

                poLS->addSubLineString( poElemLS, 1 );
            }
            else
                poLS->addSubLineString( poElemLS, 0 );

            //delete poElemLS;
        }

    }

    *piElement -= 3;
    return poLS;
}

/* -------------------------------------------------------------------- */
/*      Otherwise it is apparently unsupported.                         */
/* -------------------------------------------------------------------- */
else
{
    assert( false );
}

return NULL;

}
OGRGeometry* TranslateGeometry( SSDataBase::SSDBSDOGeometry* pSdoGeometry )
{
SSDataBase::SSGeomData * pSSGeomData = dynamic_cast 《SSDataBase::SSGeomData*>( pSdoGeometry->GetPrivateData() );

int nElemCount, nOrdCount;

nElemCount = pSSGeomData->GetElemInfo()->size();
nOrdCount = pSSGeomData->GetOrdinates()->size();

/* -------------------------------------------------------------------- */
/*      Get the GType.                                                  */
/* -------------------------------------------------------------------- */
int nGType = *( pSSGeomData->GetGType() );



/* -------------------------------------------------------------------- */
/*      Establish the dimension.                                        */
/* -------------------------------------------------------------------- */
int nDimension = MAX(2,(nGType / 1000));

/* -------------------------------------------------------------------- */
/*      Handle point data directly from built-in point info.            */
/* -------------------------------------------------------------------- */
if( ORA_GTYPE_MATCH(nGType,1) && ( pSSGeomData->GetGeomPoint() != NULL ) )
{
    double     dfX, dfY, dfZ = 0.0;

    dfX = *( pSSGeomData->GetGeomPoint()->GetX() );
    dfY = *( pSSGeomData->GetGeomPoint()->GetY() );
    dfZ = *( pSSGeomData->GetGeomPoint()->GetZ() );

    if( nDimension == 3 )
        return new OGRPoint( dfX, dfY, dfZ );
    else
        return new OGRPoint( dfX, dfY );
}

/* -------------------------------------------------------------------- */
/*      If this is a sort of container geometry, create the             */
/*      container now.                                                  */
/* -------------------------------------------------------------------- */
OGRGeometryCollection *poCollection = NULL;
OGRPolygon *poPolygon = NULL;
OGRGeometry *poParent = NULL;
OGRLineString *poLS = NULL;

if( ORA_GTYPE_MATCH(nGType,2))
    poLS = new OGRLineString();
else if( ORA_GTYPE_MATCH(nGType,3) )
    poParent = poPolygon = new OGRPolygon();
else if( ORA_GTYPE_MATCH(nGType,4) )
    poParent = poCollection = new OGRGeometryCollection();
else if( ORA_GTYPE_MATCH(nGType,5) )
    poParent = poCollection = new OGRMultiPoint();
else if( ORA_GTYPE_MATCH(nGType,6) )
    poParent = poCollection = new OGRMultiLineString();
else if( ORA_GTYPE_MATCH(nGType,7) )
    poParent = poCollection = new OGRMultiPolygon();

/* ==================================================================== */
/*      Loop over the component elements.                               */
/* ==================================================================== */
//每个SDO_ELEM_INFO属性单元由:SDO_STARTING_OFFSET、SDO_ETYPE 和SDO_INTERPRETATION 组成
for( int iElement = 0; iElement < nElemCount; iElement += 3 )
{
    int       nInterpretation, nEType;
    int       nStartOrdinal, nElemOrdCount;


    /* -------------------------------------------------------------------- */
    /*      Get the details about element from the elem_info array.         */
    /* -------------------------------------------------------------------- */

    nStartOrdinal = pSSGeomData->GetElemInfo()->at( iElement );
    nEType = pSSGeomData->GetElemInfo()->at( iElement + 1);
    nInterpretation = pSSGeomData->GetElemInfo()->at( iElement + 2 );


    if( iElement < nElemCount-3 )
    {
        int nNextStartOrdinal = pSSGeomData->GetElemInfo()->at( iElement + 3);
        nElemOrdCount = nNextStartOrdinal - nStartOrdinal;
    }
    else
        nElemOrdCount = nOrdCount - nStartOrdinal + 1;

    /* -------------------------------------------------------------------- */
    /*      Translate this element.                                         */
    /* -------------------------------------------------------------------- */
    OGRGeometry *poGeom;

    poGeom = TranslateGeometryElement( &iElement, nGType, nDimension, 
        nEType, nInterpretation,
        nStartOrdinal - 1, nElemOrdCount, pSSGeomData );

    if( poGeom == NULL )
        return NULL;

    /* -------------------------------------------------------------------- */
    /*      Based on GType do what is appropriate.                          */
    /* -------------------------------------------------------------------- */
    if( ORA_GTYPE_MATCH(nGType,2) )
    {
        //复合线已完整,
        assert(wkbFlatten(poGeom->getGeometryType()) == wkbLineString);
        return poGeom;
    }

    else if( ORA_GTYPE_MATCH(nGType,1) )
    {
        assert(wkbFlatten(poGeom->getGeometryType()) == wkbPoint);
        return poGeom;
    }

    else if( ORA_GTYPE_MATCH(nGType,3) )
    {
        assert(wkbFlatten(poGeom->getGeometryType()) == wkbLineString );
        poPolygon->addRingDirectly( (OGRLinearRing *) poGeom );
    }
    else 
    {
        assert( poCollection != NULL );
        if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint )
        {
            int  i;
            OGRMultiPoint *poMP = (OGRMultiPoint *) poGeom;

            for( i = 0; i < poMP->getNumGeometries(); i++ )
                poCollection->addGeometry( poMP->getGeometryRef(i) );
            delete poMP;
        }
        else if( nEType % 1000 == 3 )
        { 
            /* its one poly ring, create new poly or add to existing */
            if( nEType == 1003 )
            {
                if( poPolygon != NULL 
                    && poPolygon->getExteriorRing() != NULL )
                {
                    poCollection->addGeometryDirectly( poPolygon );
                    poPolygon = NULL;
                }

                poPolygon = new OGRPolygon();
            }

            if( poPolygon != NULL )
                poPolygon->addRingDirectly( (OGRLinearRing *) poGeom );
            else
            {
                assert( poPolygon != NULL );
            }
        }
        else
            poCollection->addGeometryDirectly( poGeom );
    }
}

if( poCollection != NULL 
    && poPolygon != NULL )
    poCollection->addGeometryDirectly( poPolygon );

/* -------------------------------------------------------------------- */
/*      Return resulting collection geometry.                           */
/* -------------------------------------------------------------------- */
if( poCollection == NULL )
    return poPolygon;
else
    return poCollection;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void PushElemInfo( int nOffset, int nEType, int nInterp, SSDataBase::SSGeomData* &pSSGeomData, int& nElemInfoCount )
{
std::vector* pElementInfo = pSSGeomData->GetElemInfo();
int nElemInfoMax = pElementInfo->size();
if( nElemInfoCount+3 >= nElemInfoMax )
{
nElemInfoMax = nElemInfoMax * 2 + 100;
pElementInfo->reserve( nElemInfoMax );
}
pElementInfo->push_back( nOffset );
nElemInfoCount++;
pElementInfo->push_back( nEType );
nEType++;
pElementInfo->push_back( nInterp );
nInterp++;
// pElementInfo->at( nElemInfoCount++ ) = nOffset;
// pElementInfo->at( nElemInfoCount++ ) = nEType;
// pElementInfo->at( nElemInfoCount++ ) = nInterp;
}

void PushOrdinal( double dfOrd, SSDataBase::SSGeomData* &pSSGeomData, int& nOrdinalCount )
{
std::vector * pOrdinates = pSSGeomData->GetOrdinates();
int nOrdinalMax = pOrdinates->size();

if( nOrdinalCount == nOrdinalMax )
{
    nOrdinalMax = nOrdinalMax * 2 + 100;
    pOrdinates->reserve( nOrdinalMax );
}
pOrdinates->push_back( dfOrd );
nOrdinalCount++;

/* pOrdinates->at( nOrdinalCount++ ) = dfOrd;*/
}

void TranslateElementGroup( OGRGeometry poGeometry, int nDimension, SSDataBase::SSGeomData &pSSGeomData, int& nOrdinalCount, int& nElemInfoCount )
{
switch( wkbFlatten(poGeometry->getGeometryType()) )
{
case wkbPoint:
{
OGRPoint poPoint = (OGRPoint ) poGeometry;

        PushElemInfo( nOrdinalCount+1, 1, 1, pSSGeomData, nElemInfoCount );

        PushOrdinal( poPoint->getX(), pSSGeomData, nOrdinalCount );
        PushOrdinal( poPoint->getY(), pSSGeomData, nOrdinalCount  );
        if( nDimension == 3 )
            PushOrdinal( poPoint->getZ(), pSSGeomData, nOrdinalCount  );

    }
    break;
case wkbLineString:
    {
        OGRLineString *poLine = (OGRLineString *) poGeometry;
        int  iVert;

        PushElemInfo( nOrdinalCount+1, 2, 1, pSSGeomData, nElemInfoCount );

        for( iVert = 0; iVert < poLine->getNumPoints(); iVert++ )
        {
            PushOrdinal( poLine->getX(iVert), pSSGeomData, nOrdinalCount );
            PushOrdinal( poLine->getY(iVert), pSSGeomData, nOrdinalCount );
            if( nDimension == 3 )
                PushOrdinal( poLine->getZ(iVert), pSSGeomData, nOrdinalCount );
        }
    }
    break;
case wkbPolygon:
    {
        OGRPolygon *poPoly = (OGRPolygon *) poGeometry;
        int iRing;

        for( iRing = -1; iRing < poPoly->getNumInteriorRings(); iRing++ )
        {
            OGRLinearRing *poRing;
            int            iVert;

            if( iRing == -1 )
                poRing = poPoly->getExteriorRing();
            else
                poRing = poPoly->getInteriorRing(iRing);

            if( iRing == -1 )
                PushElemInfo( nOrdinalCount+1, 1003, 1, pSSGeomData, nElemInfoCount );
            else
                PushElemInfo( nOrdinalCount+1, 2003, 1, pSSGeomData, nElemInfoCount );

            if( (iRing == -1 && poRing->isClockwise())
                || (iRing != -1 && !poRing->isClockwise()) )
            {
                for( iVert = poRing->getNumPoints()-1; iVert >= 0; iVert-- )
                {
                    PushOrdinal( poRing->getX(iVert), pSSGeomData, nOrdinalCount );
                    PushOrdinal( poRing->getY(iVert), pSSGeomData, nOrdinalCount );
                    if( nDimension == 3 )
                        PushOrdinal( poRing->getZ(iVert), pSSGeomData, nOrdinalCount );
                }
            }
            else
            {
                for( iVert = 0; iVert < poRing->getNumPoints(); iVert++ )
                {
                    PushOrdinal( poRing->getX(iVert), pSSGeomData, nOrdinalCount );
                    PushOrdinal( poRing->getY(iVert), pSSGeomData, nOrdinalCount );
                    if( nDimension == 3 )
                        PushOrdinal( poRing->getZ(iVert), pSSGeomData, nOrdinalCount );
                }
            }
        }

    }
    break;
default:
    {
        assert(false);
    }
}

}
//////////////////////////////////OGRGeometry ->SDOGeometry//////////////////
SSDataBase::SSDBSDOGeometry* TranslateToSDOGeometry( OGRGeometry * poGeometry, int *pnGType )
{
int nDimension = 3;
int nOrdinalCount = 0;
int nElemInfoCount = 0;

if( poGeometry == NULL )
    return NULL;

SSDataBase::SSDBSDOGeometry* pSSDBObject = dynamic_cast< SSDataBase::SSDBSDOGeometry* >( SSDataBase::SSDBObject::CreateObject(std::string("MDSYS.SDO_GEOMETRY")));
assert(pSSDBObject);

SSDataBase::SSGeomData* pSSGeomData = dynamic_cast<SSDataBase::SSGeomData*>( pSSDBObject->CreatePrivateData() );
assert( pSSGeomData );

/* ==================================================================== */
/*      Handle a point geometry.                                        */
/* ==================================================================== */
if( wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
{
    *pnGType = nDimension * 1000 + 1;
    OGRPoint *poPoint = (OGRPoint *) poGeometry;
    double dfX, dfY, dfZ;
    dfX = poPoint->getX();
    dfY = poPoint->getY();
    dfZ = poPoint->getZ();

    if( nDimension == 2 )
        pSSGeomData->SetGeomPoint( &dfX, &dfY, NULL );
    else
        pSSGeomData->SetGeomPoint( &dfX, &dfY, &dfZ );
}
/* ==================================================================== */
/*      Handle a line string geometry.                                  */
/* ==================================================================== */
else if( wkbFlatten(poGeometry->getGeometryType()) == wkbLineString )
{
    *pnGType = nDimension * 1000 + 2;
    TranslateElementGroup( poGeometry, nDimension, pSSGeomData, nOrdinalCount, nElemInfoCount );
}

/* ==================================================================== */
/*      Handle a polygon geometry.                                      */
/* ==================================================================== */
else if( wkbFlatten(poGeometry->getGeometryType()) == wkbPolygon )
{
    *pnGType = nDimension == 2 ? 2003 : 3003;
    TranslateElementGroup( poGeometry, nDimension, pSSGeomData, nOrdinalCount, nElemInfoCount );
}

/* ==================================================================== */
/*      Handle a multi point geometry.                                  */
/* ==================================================================== */
else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
{
    OGRMultiPoint *poMP = (OGRMultiPoint *) poGeometry;
    int  iVert;

    *pnGType = nDimension*1000 + 5;
    PushElemInfo( 1, 1, poMP->getNumGeometries(), pSSGeomData, nElemInfoCount );

    for( iVert = 0; iVert < poMP->getNumGeometries(); iVert++ )
    {
        OGRPoint *poPoint = (OGRPoint *)poMP->getGeometryRef( iVert );

        PushOrdinal( poPoint->getX(), pSSGeomData, nOrdinalCount );
        PushOrdinal( poPoint->getY(), pSSGeomData, nOrdinalCount );
        if( nDimension == 3 )
            PushOrdinal( poPoint->getZ(), pSSGeomData, nOrdinalCount );
    }
}

/* ==================================================================== */
/*      Handle other geometry collections.                              */
/* ==================================================================== */
else
{
    /* -------------------------------------------------------------------- */
    /*      Identify the GType.                                             */
    /* -------------------------------------------------------------------- */
    if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
        *pnGType = nDimension * 1000 + 6;
    else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
        *pnGType = nDimension * 1000 + 7;
    else if( wkbFlatten(poGeometry->getGeometryType()) 
        == wkbGeometryCollection )
        *pnGType = nDimension * 1000 + 4;
    else 
    {
        assert( false );

    }

    /* -------------------------------------------------------------------- */
    /*      Translate each child in turn.                                   */
    /* -------------------------------------------------------------------- */
    OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
    int  iChild;

    for( iChild = 0; iChild < poGC->getNumGeometries(); iChild++ )
        TranslateElementGroup( poGC->getGeometryRef(iChild), nDimension, pSSGeomData, nOrdinalCount, nElemInfoCount );

}

pSSGeomData->SetGType( *pnGType );
return pSSDBObject;

}

文章参考:爱图–UpdooGIS博客内容,oraclespatial 空间信息管理书籍。
代码参考:ogr源码

转载自:https://blog.csdn.net/lly276586465/article/details/78686383

You may also like...