OGRGeometry* BuildOgrPolygon(Polygon* poly, OGRCoordinateTransformation* transform) { OGRPolygon* result = new OGRPolygon(); list<Point*>* pOuter = poly->outerRing; list<Point*>::iterator ringIter; OGRLinearRing* ring = new OGRLinearRing(); for (ringIter = pOuter->begin(); ringIter != pOuter->end(); ringIter++) { double x = (*ringIter)->X; double y = (*ringIter)->Y; if (transform != NULL) transform->Transform(1, &x, &y); ring->addPoint(x, y); } result->addRingDirectly(ring); list<list<Point *>*>* innerRings = poly->innerRings; list<list<Point *>*>::iterator ringsIter; for (ringsIter = innerRings->begin(); ringsIter != innerRings->end(); ringsIter++) { ring = new OGRLinearRing(); list<Point*>* currRing = *ringsIter; for (ringIter = currRing->begin(); ringIter != currRing->end(); ringIter++) { double x = (*ringIter)->X; double y = (*ringIter)->Y; if (transform != NULL) transform->Transform(1, &x, &y); ring->addPoint(x, y); } result->addRingDirectly(ring); } result->closeRings(); return result; }
OGRFeature *OGRCADLayer::GetFeature( GIntBig nFID ) { if( poCADLayer.getGeometryCount() <= static_cast<size_t>(nFID) || nFID < 0 ) { return nullptr; } OGRFeature *poFeature = nullptr; CADGeometry *poCADGeometry = poCADLayer.getGeometry( static_cast<size_t>(nFID) ); if( nullptr == poCADGeometry || GetLastErrorCode() != CADErrorCodes::SUCCESS ) { CPLError( CE_Failure, CPLE_NotSupported, "Failed to get geometry with ID = " CPL_FRMT_GIB " from layer \"%s\". Libopencad errorcode: %d", nFID, poCADLayer.getName().c_str(), GetLastErrorCode() ); return nullptr; } poFeature = new OGRFeature( poFeatureDefn ); poFeature->SetFID( nFID ); poFeature->SetField( FIELD_NAME_THICKNESS, poCADGeometry->getThickness() ); if( !poCADGeometry->getEED().empty() ) { std::vector<std::string> asGeometryEED = poCADGeometry->getEED(); std::string sEEDAsOneString = ""; for ( std::vector<std::string>::const_iterator iter = asGeometryEED.cbegin(); iter != asGeometryEED.cend(); ++iter ) { sEEDAsOneString += *iter; sEEDAsOneString += ' '; } poFeature->SetField( FIELD_NAME_EXT_DATA, sEEDAsOneString.c_str() ); } RGBColor stRGB = poCADGeometry->getColor(); CPLString sHexColor; sHexColor.Printf("#%02X%02X%02X%02X", stRGB.R, stRGB.G, stRGB.B, 255); poFeature->SetField( FIELD_NAME_COLOR, sHexColor ); CPLString sStyle; sStyle.Printf("PEN(c:%s,w:5px)", sHexColor.c_str()); poFeature->SetStyleString( sStyle ); std::vector< CADAttrib > oBlockAttrs = poCADGeometry->getBlockAttributes(); for( const CADAttrib& oAttrib : oBlockAttrs ) { CPLString osTag = oAttrib.getTag(); auto featureAttrIt = asFeaturesAttributes.find( osTag ); if( featureAttrIt != asFeaturesAttributes.end()) { poFeature->SetField(*featureAttrIt, oAttrib.getTextValue().c_str()); } } switch( poCADGeometry->getType() ) { case CADGeometry::POINT: { CADPoint3D * const poCADPoint = ( CADPoint3D* ) poCADGeometry; CADVector stPositionVector = poCADPoint->getPosition(); poFeature->SetGeometryDirectly( new OGRPoint( stPositionVector.getX(), stPositionVector.getY(), stPositionVector.getZ() ) ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADPoint" ); break; } case CADGeometry::LINE: { CADLine * const poCADLine = ( CADLine* ) poCADGeometry; OGRLineString *poLS = new OGRLineString(); poLS->addPoint( poCADLine->getStart().getPosition().getX(), poCADLine->getStart().getPosition().getY(), poCADLine->getStart().getPosition().getZ() ); poLS->addPoint( poCADLine->getEnd().getPosition().getX(), poCADLine->getEnd().getPosition().getY(), poCADLine->getEnd().getPosition().getZ() ); poFeature->SetGeometryDirectly( poLS ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADLine" ); break; } case CADGeometry::SOLID: { CADSolid * const poCADSolid = ( CADSolid* ) poCADGeometry; OGRPolygon * poPoly = new OGRPolygon(); OGRLinearRing * poLR = new OGRLinearRing(); std::vector<CADVector> astSolidCorners = poCADSolid->getCorners(); for( size_t i = 0; i < astSolidCorners.size(); ++i ) { poLR->addPoint( astSolidCorners[i].getX(), astSolidCorners[i].getY(), astSolidCorners[i].getZ()); } poPoly->addRingDirectly( poLR ); poPoly->closeRings(); poFeature->SetGeometryDirectly( poPoly ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADSolid" ); break; } case CADGeometry::CIRCLE: { CADCircle * poCADCircle = static_cast<CADCircle*>(poCADGeometry); OGRCircularString * poCircle = new OGRCircularString(); CADVector stCircleCenter = poCADCircle->getPosition(); OGRPoint oCirclePoint1; oCirclePoint1.setX( stCircleCenter.getX() - poCADCircle->getRadius() ); oCirclePoint1.setY( stCircleCenter.getY() ); oCirclePoint1.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint1 ); OGRPoint oCirclePoint2; oCirclePoint2.setX( stCircleCenter.getX() ); oCirclePoint2.setY( stCircleCenter.getY() + poCADCircle->getRadius() ); oCirclePoint2.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint2 ); OGRPoint oCirclePoint3; oCirclePoint3.setX( stCircleCenter.getX() + poCADCircle->getRadius() ); oCirclePoint3.setY( stCircleCenter.getY() ); oCirclePoint3.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint3 ); OGRPoint oCirclePoint4; oCirclePoint4.setX( stCircleCenter.getX() ); oCirclePoint4.setY( stCircleCenter.getY() - poCADCircle->getRadius() ); oCirclePoint4.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint4 ); // Close the circle poCircle->addPoint( &oCirclePoint1 ); /*NOTE: The alternative way: OGRGeometry *poCircle = OGRGeometryFactory::approximateArcAngles( poCADCircle->getPosition().getX(), poCADCircle->getPosition().getY(), poCADCircle->getPosition().getZ(), poCADCircle->getRadius(), poCADCircle->getRadius(), 0.0, 0.0, 360.0, 0.0 ); */ poFeature->SetGeometryDirectly( poCircle ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADCircle" ); break; } case CADGeometry::ARC: { CADArc * poCADArc = static_cast<CADArc*>(poCADGeometry); OGRCircularString * poCircle = new OGRCircularString(); // Need at least 3 points in arc double dfStartAngle = poCADArc->getStartingAngle() * DEG2RAD; double dfEndAngle = poCADArc->getEndingAngle() * DEG2RAD; double dfMidAngle = (dfEndAngle + dfStartAngle) / 2; CADVector stCircleCenter = poCADArc->getPosition(); OGRPoint oCirclePoint; oCirclePoint.setX( stCircleCenter.getX() + poCADArc->getRadius() * cos( dfStartAngle ) ); oCirclePoint.setY( stCircleCenter.getY() + poCADArc->getRadius() * sin( dfStartAngle ) ); oCirclePoint.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint ); oCirclePoint.setX( stCircleCenter.getX() + poCADArc->getRadius() * cos( dfMidAngle ) ); oCirclePoint.setY( stCircleCenter.getY() + poCADArc->getRadius() * sin( dfMidAngle ) ); oCirclePoint.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint ); oCirclePoint.setX( stCircleCenter.getX() + poCADArc->getRadius() * cos( dfEndAngle ) ); oCirclePoint.setY( stCircleCenter.getY() + poCADArc->getRadius() * sin( dfEndAngle ) ); oCirclePoint.setZ( stCircleCenter.getZ() ); poCircle->addPoint( &oCirclePoint ); /*NOTE: alternative way: OGRGeometry * poArc = OGRGeometryFactory::approximateArcAngles( poCADArc->getPosition().getX(), poCADArc->getPosition().getY(), poCADArc->getPosition().getZ(), poCADArc->getRadius(), poCADArc->getRadius(), 0.0, dfStartAngle, dfStartAngle > dfEndAngle ? ( dfEndAngle + 360.0f ) : dfEndAngle, 0.0 ); */ poFeature->SetGeometryDirectly( poCircle ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADArc" ); break; } case CADGeometry::FACE3D: { CADFace3D * const poCADFace = ( CADFace3D* ) poCADGeometry; OGRPolygon * poPoly = new OGRPolygon(); OGRLinearRing * poLR = new OGRLinearRing(); for ( size_t i = 0; i < 3; ++i ) { poLR->addPoint( poCADFace->getCorner( i ).getX(), poCADFace->getCorner( i ).getY(), poCADFace->getCorner( i ).getZ() ); } if ( !(poCADFace->getCorner( 2 ) == poCADFace->getCorner( 3 )) ) { poLR->addPoint( poCADFace->getCorner( 3 ).getX(), poCADFace->getCorner( 3 ).getY(), poCADFace->getCorner( 3 ).getZ() ); } poPoly->addRingDirectly( poLR ); poPoly->closeRings(); poFeature->SetGeometryDirectly( poPoly ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADFace3D" ); break; } case CADGeometry::LWPOLYLINE: { CADLWPolyline * const poCADLWPolyline = ( CADLWPolyline* ) poCADGeometry; poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADLWPolyline" ); /* * Excessive check, like in DXF driver. * I tried to make a single-point polyline, but couldn't make it. * Probably this check should be removed. */ if( poCADLWPolyline->getVertexCount() == 1 ) { poFeature->SetGeometryDirectly( new OGRPoint( poCADLWPolyline->getVertex(0).getX(), poCADLWPolyline->getVertex(0).getY(), poCADLWPolyline->getVertex(0).getZ() ) ); break; } /* * If polyline has no arcs, handle it in easy way. */ OGRLineString * poLS = new OGRLineString(); if( poCADLWPolyline->getBulges().empty() ) { for( size_t i = 0; i < poCADLWPolyline->getVertexCount(); ++i ) { CADVector stVertex = poCADLWPolyline->getVertex( i ); poLS->addPoint( stVertex.getX(), stVertex.getY(), stVertex.getZ() ); } poFeature->SetGeometryDirectly( poLS ); break; } /* * Last case - if polyline has mixed arcs and lines. */ bool bLineStringStarted = false; std::vector< double > adfBulges = poCADLWPolyline->getBulges(); const size_t nCount = std::min(adfBulges.size(), poCADLWPolyline->getVertexCount()); for( size_t iCurrentVertex = 0; iCurrentVertex + 1 < nCount; iCurrentVertex++ ) { CADVector stCurrentVertex = poCADLWPolyline->getVertex( iCurrentVertex ); CADVector stNextVertex = poCADLWPolyline->getVertex( iCurrentVertex + 1 ); double dfLength = sqrt( pow( stNextVertex.getX() - stCurrentVertex.getX(), 2 ) + pow( stNextVertex.getY() - stCurrentVertex.getY(), 2 ) ); /* * Handling straight polyline segment. */ if( ( dfLength == 0 ) || ( adfBulges[iCurrentVertex] == 0 ) ) { if( !bLineStringStarted ) { poLS->addPoint( stCurrentVertex.getX(), stCurrentVertex.getY(), stCurrentVertex.getZ() ); bLineStringStarted = true; } poLS->addPoint( stNextVertex.getX(), stNextVertex.getY(), stNextVertex.getZ() ); } else { double dfSegmentBulge = adfBulges[iCurrentVertex]; double dfH = ( dfSegmentBulge * dfLength ) / 2; if( dfH == 0.0 ) dfH = 1.0; // just to avoid a division by zero double dfRadius = ( dfH / 2 ) + ( dfLength * dfLength / ( 8 * dfH ) ); double dfOgrArcRotation = 0, dfOgrArcRadius = fabs( dfRadius ); /* * Set arc's direction and keep bulge positive. */ bool bClockwise = ( dfSegmentBulge < 0 ); if( bClockwise ) dfSegmentBulge *= -1; /* * Get arc's center point. */ double dfSaggita = fabs( dfSegmentBulge * ( dfLength / 2.0 ) ); double dfApo = bClockwise ? -( dfOgrArcRadius - dfSaggita ) : -( dfSaggita - dfOgrArcRadius ); CADVector stVertex; stVertex.setX( stCurrentVertex.getX() - stNextVertex.getX() ); stVertex.setY( stCurrentVertex.getY() - stNextVertex.getY() ); stVertex.setZ( stCurrentVertex.getZ() ); CADVector stMidPoint; stMidPoint.setX( stNextVertex.getX() + 0.5 * stVertex.getX() ); stMidPoint.setY( stNextVertex.getY() + 0.5 * stVertex.getY() ); stMidPoint.setZ( stVertex.getZ() ); CADVector stPperp; stPperp.setX( stVertex.getY() ); stPperp.setY( -stVertex.getX() ); double dfStPperpLength = sqrt( stPperp.getX() * stPperp.getX() + stPperp.getY() * stPperp.getY() ); // TODO: Check that length isnot 0 stPperp.setX( stPperp.getX() / dfStPperpLength ); stPperp.setY( stPperp.getY() / dfStPperpLength ); CADVector stOgrArcCenter; stOgrArcCenter.setX( stMidPoint.getX() + ( stPperp.getX() * dfApo ) ); stOgrArcCenter.setY( stMidPoint.getY() + ( stPperp.getY() * dfApo ) ); /* * Get the line's general vertical direction ( -1 = down, +1 = up ). */ double dfLineDir = stNextVertex.getY() > stCurrentVertex.getY() ? 1.0f : -1.0f; /* * Get arc's starting angle. */ double dfA = atan2( ( stOgrArcCenter.getY() - stCurrentVertex.getY() ), ( stOgrArcCenter.getX() - stCurrentVertex.getX() ) ) * DEG2RAD; if( bClockwise && ( dfLineDir == 1.0 ) ) dfA += ( dfLineDir * 180.0 ); double dfOgrArcStartAngle = dfA > 0.0 ? -( dfA - 180.0 ) : -( dfA + 180.0 ); /* * Get arc's ending angle. */ dfA = atan2( ( stOgrArcCenter.getY() - stNextVertex.getY() ), ( stOgrArcCenter.getX() - stNextVertex.getX() ) ) * DEG2RAD; if( bClockwise && ( dfLineDir == 1.0 ) ) dfA += ( dfLineDir * 180.0 ); double dfOgrArcEndAngle = dfA > 0.0 ? -( dfA - 180.0 ) : -( dfA + 180.0 ); if( !bClockwise && ( dfOgrArcStartAngle < dfOgrArcEndAngle) ) dfOgrArcEndAngle = -180.0 + ( dfLineDir * dfA ); if( bClockwise && ( dfOgrArcStartAngle > dfOgrArcEndAngle ) ) dfOgrArcEndAngle += 360.0; /* * Flip arc's rotation if necessary. */ if( bClockwise && ( dfLineDir == 1.0 ) ) dfOgrArcRotation = dfLineDir * 180.0; /* * Tessellate the arc segment and append to the linestring. */ OGRLineString * poArcpoLS = ( OGRLineString * ) OGRGeometryFactory::approximateArcAngles( stOgrArcCenter.getX(), stOgrArcCenter.getY(), stOgrArcCenter.getZ(), dfOgrArcRadius, dfOgrArcRadius, dfOgrArcRotation, dfOgrArcStartAngle,dfOgrArcEndAngle, 0.0 ); poLS->addSubLineString( poArcpoLS ); delete( poArcpoLS ); } } if( poCADLWPolyline->isClosed() ) { poLS->addPoint( poCADLWPolyline->getVertex(0).getX(), poCADLWPolyline->getVertex(0).getY(), poCADLWPolyline->getVertex(0).getZ() ); } poFeature->SetGeometryDirectly( poLS ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADLWPolyline" ); break; } // TODO: Unsupported smooth lines case CADGeometry::POLYLINE3D: { CADPolyline3D * const poCADPolyline3D = ( CADPolyline3D* ) poCADGeometry; OGRLineString * poLS = new OGRLineString(); for( size_t i = 0; i < poCADPolyline3D->getVertexCount(); ++i ) { CADVector stVertex = poCADPolyline3D->getVertex( i ); poLS->addPoint( stVertex.getX(), stVertex.getY(), stVertex.getZ() ); } poFeature->SetGeometryDirectly( poLS ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADPolyline3D" ); break; } case CADGeometry::TEXT: { CADText * const poCADText = ( CADText * ) poCADGeometry; OGRPoint * poPoint = new OGRPoint( poCADText->getPosition().getX(), poCADText->getPosition().getY(), poCADText->getPosition().getZ() ); CPLString sTextValue = CADRecode( poCADText->getTextValue(), nDWGEncoding ); poFeature->SetField( FIELD_NAME_TEXT, sTextValue ); poFeature->SetGeometryDirectly( poPoint ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADText" ); sStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",c:%s)", sTextValue.c_str(), sHexColor.c_str()); poFeature->SetStyleString( sStyle ); break; } case CADGeometry::MTEXT: { CADMText * const poCADMText = ( CADMText * ) poCADGeometry; OGRPoint * poPoint = new OGRPoint( poCADMText->getPosition().getX(), poCADMText->getPosition().getY(), poCADMText->getPosition().getZ() ); CPLString sTextValue = CADRecode( poCADMText->getTextValue(), nDWGEncoding ); poFeature->SetField( FIELD_NAME_TEXT, sTextValue ); poFeature->SetGeometryDirectly( poPoint ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADMText" ); sStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",c:%s)", sTextValue.c_str(), sHexColor.c_str()); poFeature->SetStyleString( sStyle ); break; } case CADGeometry::SPLINE: { CADSpline * const poCADSpline = ( CADSpline * ) poCADGeometry; OGRLineString * poLS = new OGRLineString(); // TODO: Interpolate spline as points or curves for( size_t i = 0; i < poCADSpline->getControlPoints().size(); ++i ) { poLS->addPoint( poCADSpline->getControlPoints()[i].getX(), poCADSpline->getControlPoints()[i].getY(), poCADSpline->getControlPoints()[i].getZ() ); } poFeature->SetGeometryDirectly( poLS ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADSpline" ); break; } case CADGeometry::ELLIPSE: { CADEllipse * poCADEllipse = static_cast<CADEllipse*>(poCADGeometry); // FIXME: Start/end angles should be swapped to work exactly as DXF driver. // is it correct? double dfStartAngle = -1 * poCADEllipse->getEndingAngle() * DEG2RAD; double dfEndAngle = -1 * poCADEllipse->getStartingAngle() * DEG2RAD; double dfAxisRatio = poCADEllipse->getAxisRatio(); dfStartAngle = fmod(dfStartAngle, 360.0); dfEndAngle = fmod(dfEndAngle, 360.0); if( dfStartAngle > dfEndAngle ) dfEndAngle += 360.0; CADVector vectPosition = poCADEllipse->getPosition(); CADVector vectSMAxis = poCADEllipse->getSMAxis(); double dfPrimaryRadius, dfSecondaryRadius; double dfRotation; dfPrimaryRadius = sqrt( vectSMAxis.getX() * vectSMAxis.getX() + vectSMAxis.getY() * vectSMAxis.getY() + vectSMAxis.getZ() * vectSMAxis.getZ() ); dfSecondaryRadius = dfAxisRatio * dfPrimaryRadius; dfRotation = -1 * atan2( vectSMAxis.getY(), vectSMAxis.getX() ) * DEG2RAD; OGRGeometry *poEllipse = OGRGeometryFactory::approximateArcAngles( vectPosition.getX(), vectPosition.getY(), vectPosition.getZ(), dfPrimaryRadius, dfSecondaryRadius, dfRotation, dfStartAngle, dfEndAngle, 0.0 ); poFeature->SetGeometryDirectly( poEllipse ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADEllipse" ); break; } case CADGeometry::ATTDEF: { CADAttdef * const poCADAttdef = ( CADAttdef* ) poCADGeometry; OGRPoint * poPoint = new OGRPoint( poCADAttdef->getPosition().getX(), poCADAttdef->getPosition().getY(), poCADAttdef->getPosition().getZ() ); CPLString sTextValue = CADRecode( poCADAttdef->getTag(), nDWGEncoding ); poFeature->SetField( FIELD_NAME_TEXT, sTextValue ); poFeature->SetGeometryDirectly( poPoint ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADAttdef" ); sStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",c:%s)", sTextValue.c_str(), sHexColor.c_str()); poFeature->SetStyleString( sStyle ); break; } default: { CPLError( CE_Warning, CPLE_NotSupported, "Unhandled feature. Skipping it." ); poFeature->SetField( FIELD_NAME_GEOMTYPE, "CADUnknown" ); delete poCADGeometry; return poFeature; } } delete poCADGeometry; poFeature->GetGeometryRef()->assignSpatialReference( poSpatialRef ); return poFeature; }