OGRErr OGRDXFWriterLayer::WritePOLYLINE( OGRFeature *poFeature, const OGRGeometry *poGeom ) { /* -------------------------------------------------------------------- */ /* For now we handle multilinestrings by writing a series of */ /* entities. */ /* -------------------------------------------------------------------- */ if( poGeom == nullptr ) poGeom = poFeature->GetGeometryRef(); if ( poGeom->IsEmpty() ) { return OGRERR_NONE; } if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon || wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ) { const OGRGeometryCollection *poGC = poGeom->toGeometryCollection(); OGRErr eErr = OGRERR_NONE; for( auto&& poMember: *poGC ) { eErr = WritePOLYLINE( poFeature, poMember ); if( eErr != OGRERR_NONE ) break; } return eErr; } /* -------------------------------------------------------------------- */ /* Polygons are written with on entity per ring. */ /* -------------------------------------------------------------------- */ if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon || wkbFlatten(poGeom->getGeometryType()) == wkbTriangle) { const OGRPolygon *poPoly = poGeom->toPolygon(); OGRErr eErr = OGRERR_NONE; for( auto&& poRing: *poPoly ) { eErr = WritePOLYLINE( poFeature, poRing ); if( eErr != OGRERR_NONE ) break; } return eErr; } /* -------------------------------------------------------------------- */ /* Do we now have a geometry we can work with? */ /* -------------------------------------------------------------------- */ if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString ) return OGRERR_UNSUPPORTED_GEOMETRY_TYPE; const OGRLineString *poLS = poGeom->toLineString(); /* -------------------------------------------------------------------- */ /* Write as a lightweight polygon, */ /* or as POLYLINE if the line contains different heights */ /* -------------------------------------------------------------------- */ int bHasDifferentZ = FALSE; if( poLS->getGeometryType() == wkbLineString25D ) { double z0 = poLS->getZ(0); for( int iVert = 0; iVert < poLS->getNumPoints(); iVert++ ) { if (z0 != poLS->getZ(iVert)) { bHasDifferentZ = TRUE; break; } } } WriteValue( 0, bHasDifferentZ ? "POLYLINE" : "LWPOLYLINE" ); WriteCore( poFeature ); WriteValue( 100, "AcDbEntity" ); if( bHasDifferentZ ) { WriteValue( 100, "AcDb3dPolyline" ); WriteValue( 10, 0.0 ); WriteValue( 20, 0.0 ); WriteValue( 30, 0.0 ); } else WriteValue( 100, "AcDbPolyline" ); if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) ) WriteValue( 70, 1 + (bHasDifferentZ ? 8 : 0) ); else WriteValue( 70, 0 + (bHasDifferentZ ? 8 : 0) ); if( !bHasDifferentZ ) WriteValue( 90, poLS->getNumPoints() ); else WriteValue( 66, "1" ); // Vertex Flag /* -------------------------------------------------------------------- */ /* Do we have styling information? */ /* -------------------------------------------------------------------- */ OGRStyleTool *poTool = nullptr; OGRStyleMgr oSM; if( poFeature->GetStyleString() != nullptr ) { oSM.InitFromFeature( poFeature ); if( oSM.GetPartCount() > 0 ) poTool = oSM.GetPart(0); } /* -------------------------------------------------------------------- */ /* Handle a PEN tool to control drawing color and width. */ /* Perhaps one day also dottedness, etc. */ /* -------------------------------------------------------------------- */ if( poTool && poTool->GetType() == OGRSTCPen ) { OGRStylePen *poPen = (OGRStylePen *) poTool; GBool bDefault; if( poPen->Color(bDefault) != nullptr && !bDefault ) WriteValue( 62, ColorStringToDXFColor( poPen->Color(bDefault) ) ); // we want to fetch the width in ground units. poPen->SetUnit( OGRSTUGround, 1.0 ); const double dfWidth = poPen->Width(bDefault); if( !bDefault ) WriteValue( 370, (int) floor(dfWidth * 100 + 0.5) ); } /* -------------------------------------------------------------------- */ /* Do we have a Linetype for the feature? */ /* -------------------------------------------------------------------- */ CPLString osLineType = poFeature->GetFieldAsString( "Linetype" ); double dfLineTypeScale = 0.0; bool bGotLinetype = false; if( !osLineType.empty() ) { std::vector<double> adfLineType = poDS->oHeaderDS.LookupLineType( osLineType ); if( adfLineType.empty() && oNewLineTypes.count(osLineType) > 0 ) adfLineType = oNewLineTypes[osLineType]; if( !adfLineType.empty() ) { bGotLinetype = true; WriteValue( 6, osLineType ); // If the given linetype is proportional to the linetype data // in the style string, then apply a linetype scale if( poTool != nullptr && poTool->GetType() == OGRSTCPen ) { std::vector<double> adfDefinition = PrepareLineTypeDefinition( static_cast<OGRStylePen *>( poTool ) ); if( !adfDefinition.empty() ) { dfLineTypeScale = IsLineTypeProportional( adfLineType, adfDefinition ); if( dfLineTypeScale != 0.0 && fabs( dfLineTypeScale - 1.0 ) > 1e-4 ) { WriteValue( 48, dfLineTypeScale ); } } } } } if( !bGotLinetype && poTool != nullptr && poTool->GetType() == OGRSTCPen ) { std::vector<double> adfDefinition = PrepareLineTypeDefinition( static_cast<OGRStylePen *>( poTool ) ); if( !adfDefinition.empty() ) { // Is this definition already created and named? for( const auto& oPair : poDS->oHeaderDS.GetLineTypeTable() ) { dfLineTypeScale = IsLineTypeProportional( oPair.second, adfDefinition ); if( dfLineTypeScale != 0.0 ) { osLineType = oPair.first; break; } } if( dfLineTypeScale == 0.0 ) { for( const auto& oPair : oNewLineTypes ) { dfLineTypeScale = IsLineTypeProportional( oPair.second, adfDefinition ); if( dfLineTypeScale != 0.0 ) { osLineType = oPair.first; break; } } } // If not, create an automatic name for it. if( osLineType == "" ) { dfLineTypeScale = 1.0; do { osLineType.Printf( "AutoLineType-%d", nNextAutoID++ ); } while( poDS->oHeaderDS.LookupLineType(osLineType).size() > 0 ); } // If it isn't already defined, add it now. if( poDS->oHeaderDS.LookupLineType( osLineType ).empty() && oNewLineTypes.count( osLineType ) == 0 ) { oNewLineTypes[osLineType] = adfDefinition; } WriteValue( 6, osLineType ); if( dfLineTypeScale != 0.0 && fabs( dfLineTypeScale - 1.0 ) > 1e-4 ) { WriteValue( 48, dfLineTypeScale ); } } } /* -------------------------------------------------------------------- */ /* Write the vertices */ /* -------------------------------------------------------------------- */ if( !bHasDifferentZ && poLS->getGeometryType() == wkbLineString25D ) { // if LWPOLYLINE with Z write it only once if( !WriteValue( 38, poLS->getZ(0) ) ) return OGRERR_FAILURE; } for( int iVert = 0; iVert < poLS->getNumPoints(); iVert++ ) { if( bHasDifferentZ ) { WriteValue( 0, "VERTEX" ); WriteValue( 100, "AcDbEntity" ); WriteValue( 100, "AcDbVertex" ); WriteValue( 100, "AcDb3dPolylineVertex" ); WriteCore( poFeature ); } WriteValue( 10, poLS->getX(iVert) ); if( !WriteValue( 20, poLS->getY(iVert) ) ) return OGRERR_FAILURE; if( bHasDifferentZ ) { if( !WriteValue( 30 , poLS->getZ(iVert) ) ) return OGRERR_FAILURE; WriteValue( 70, 32 ); } } if( bHasDifferentZ ) { WriteValue( 0, "SEQEND" ); WriteCore( poFeature ); WriteValue( 100, "AcDbEntity" ); } delete poTool; return OGRERR_NONE; #ifdef notdef /* -------------------------------------------------------------------- */ /* Alternate unmaintained implementation as a polyline entity. */ /* -------------------------------------------------------------------- */ WriteValue( 0, "POLYLINE" ); WriteCore( poFeature ); WriteValue( 100, "AcDbEntity" ); WriteValue( 100, "AcDbPolyline" ); if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) ) WriteValue( 70, 1 ); else WriteValue( 70, 0 ); WriteValue( 66, "1" ); for( int iVert = 0; iVert < poLS->getNumPoints(); iVert++ ) { WriteValue( 0, "VERTEX" ); WriteValue( 8, "0" ); WriteValue( 10, poLS->getX(iVert) ); if( !WriteValue( 20, poLS->getY(iVert) ) ) return OGRERR_FAILURE; if( poLS->getGeometryType() == wkbLineString25D ) { if( !WriteValue( 30, poLS->getZ(iVert) ) ) return OGRERR_FAILURE; } } WriteValue( 0, "SEQEND" ); WriteValue( 8, "0" ); return OGRERR_NONE; #endif }
OGRErr OGRDXFWriterLayer::WritePOLYLINE( OGRFeature *poFeature, OGRGeometry *poGeom ) { /* -------------------------------------------------------------------- */ /* For now we handle multilinestrings by writing a series of */ /* entities. */ /* -------------------------------------------------------------------- */ if( poGeom == NULL ) poGeom = poFeature->GetGeometryRef(); if ( poGeom->IsEmpty() ) { return OGRERR_NONE; } if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon || wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ) { OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom; int iGeom; OGRErr eErr = OGRERR_NONE; for( iGeom = 0; eErr == OGRERR_NONE && iGeom < poGC->getNumGeometries(); iGeom++ ) { eErr = WritePOLYLINE( poFeature, poGC->getGeometryRef( iGeom ) ); } return eErr; } /* -------------------------------------------------------------------- */ /* Polygons are written with on entity per ring. */ /* -------------------------------------------------------------------- */ if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) { OGRPolygon *poPoly = (OGRPolygon *) poGeom; int iGeom; OGRErr eErr; eErr = WritePOLYLINE( poFeature, poPoly->getExteriorRing() ); for( iGeom = 0; eErr == OGRERR_NONE && iGeom < poPoly->getNumInteriorRings(); iGeom++ ) { eErr = WritePOLYLINE( poFeature, poPoly->getInteriorRing(iGeom) ); } return eErr; } /* -------------------------------------------------------------------- */ /* Do we now have a geometry we can work with? */ /* -------------------------------------------------------------------- */ if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString ) return OGRERR_UNSUPPORTED_GEOMETRY_TYPE; OGRLineString *poLS = (OGRLineString *) poGeom; /* -------------------------------------------------------------------- */ /* Write as a lightweight polygon, */ /* or as POLYLINE if the line contains different heights */ /* -------------------------------------------------------------------- */ int bHasDifferentZ = FALSE; if( poLS->getGeometryType() == wkbLineString25D ) { double z0 = poLS->getZ(0); for( int iVert = 0; iVert < poLS->getNumPoints(); iVert++ ) { if (z0 != poLS->getZ(iVert)) { bHasDifferentZ = TRUE; break; } } } WriteValue( 0, bHasDifferentZ ? "POLYLINE" : "LWPOLYLINE" ); WriteCore( poFeature ); WriteValue( 100, "AcDbEntity" ); if( bHasDifferentZ ) { WriteValue( 100, "AcDb3dPolyline" ); WriteValue( 10, 0.0 ); WriteValue( 20, 0.0 ); WriteValue( 30, 0.0 ); } else WriteValue( 100, "AcDbPolyline" ); if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) ) WriteValue( 70, 1 + (bHasDifferentZ ? 8 : 0) ); else WriteValue( 70, 0 + (bHasDifferentZ ? 8 : 0) ); if( !bHasDifferentZ ) WriteValue( 90, poLS->getNumPoints() ); else WriteValue( 66, "1" ); // Vertex Flag /* -------------------------------------------------------------------- */ /* Do we have styling information? */ /* -------------------------------------------------------------------- */ OGRStyleTool *poTool = NULL; OGRStyleMgr oSM; if( poFeature->GetStyleString() != NULL ) { oSM.InitFromFeature( poFeature ); if( oSM.GetPartCount() > 0 ) poTool = oSM.GetPart(0); } /* -------------------------------------------------------------------- */ /* Handle a PEN tool to control drawing color and width. */ /* Perhaps one day also dottedness, etc. */ /* -------------------------------------------------------------------- */ if( poTool && poTool->GetType() == OGRSTCPen ) { OGRStylePen *poPen = (OGRStylePen *) poTool; GBool bDefault; if( poPen->Color(bDefault) != NULL && !bDefault ) WriteValue( 62, ColorStringToDXFColor( poPen->Color(bDefault) ) ); // we want to fetch the width in ground units. poPen->SetUnit( OGRSTUGround, 1.0 ); double dfWidth = poPen->Width(bDefault); if( !bDefault ) WriteValue( 370, (int) floor(dfWidth * 100 + 0.5) ); } /* -------------------------------------------------------------------- */ /* Do we have a Linetype for the feature? */ /* -------------------------------------------------------------------- */ CPLString osLineType = poFeature->GetFieldAsString( "Linetype" ); if( osLineType.size() > 0 && (poDS->oHeaderDS.LookupLineType( osLineType ) != NULL || oNewLineTypes.count(osLineType) > 0 ) ) { // Already define -> just reference it. WriteValue( 6, osLineType ); } else if( poTool != NULL && poTool->GetType() == OGRSTCPen ) { CPLString osDefinition = PrepareLineTypeDefinition( poFeature, poTool ); if( osDefinition != "" && osLineType == "" ) { // Is this definition already created and named? std::map<CPLString,CPLString>::iterator it; for( it = oNewLineTypes.begin(); it != oNewLineTypes.end(); it++ ) { if( (*it).second == osDefinition ) { osLineType = (*it).first; break; } } // create an automatic name for it. if( osLineType == "" ) { do { osLineType.Printf( "AutoLineType-%d", nNextAutoID++ ); } while( poDS->oHeaderDS.LookupLineType(osLineType) != NULL ); } } // If it isn't already defined, add it now. if( osDefinition != "" && oNewLineTypes.count(osLineType) == 0 ) { oNewLineTypes[osLineType] = osDefinition; WriteValue( 6, osLineType ); } } /* -------------------------------------------------------------------- */ /* Write the vertices */ /* -------------------------------------------------------------------- */ if( !bHasDifferentZ && poLS->getGeometryType() == wkbLineString25D ) { // if LWPOLYLINE with Z write it only once if( !WriteValue( 38, poLS->getZ(0) ) ) return OGRERR_FAILURE; } int iVert; for( iVert = 0; iVert < poLS->getNumPoints(); iVert++ ) { if( bHasDifferentZ ) { WriteValue( 0, "VERTEX" ); WriteValue( 100, "AcDbEntity" ); WriteValue( 100, "AcDbVertex" ); WriteValue( 100, "AcDb3dPolylineVertex" ); WriteCore( poFeature ); } WriteValue( 10, poLS->getX(iVert) ); if( !WriteValue( 20, poLS->getY(iVert) ) ) return OGRERR_FAILURE; if( bHasDifferentZ ) { if( !WriteValue( 30 , poLS->getZ(iVert) ) ) return OGRERR_FAILURE; WriteValue( 70, 32 ); } } if( bHasDifferentZ ) { WriteValue( 0, "SEQEND" ); WriteCore( poFeature ); WriteValue( 100, "AcDbEntity" ); } delete poTool; return OGRERR_NONE; #ifdef notdef /* -------------------------------------------------------------------- */ /* Alternate unmaintained implementation as a polyline entity. */ /* -------------------------------------------------------------------- */ WriteValue( 0, "POLYLINE" ); WriteCore( poFeature ); WriteValue( 100, "AcDbEntity" ); WriteValue( 100, "AcDbPolyline" ); if( EQUAL( poGeom->getGeometryName(), "LINEARRING" ) ) WriteValue( 70, 1 ); else WriteValue( 70, 0 ); WriteValue( 66, "1" ); int iVert; for( iVert = 0; iVert < poLS->getNumPoints(); iVert++ ) { WriteValue( 0, "VERTEX" ); WriteValue( 8, "0" ); WriteValue( 10, poLS->getX(iVert) ); if( !WriteValue( 20, poLS->getY(iVert) ) ) return OGRERR_FAILURE; if( poLS->getGeometryType() == wkbLineString25D ) { if( !WriteValue( 30, poLS->getZ(iVert) ) ) return OGRERR_FAILURE; } } WriteValue( 0, "SEQEND" ); WriteValue( 8, "0" ); return OGRERR_NONE; #endif }
OGRErr OGRDXFWriterLayer::ICreateFeature( OGRFeature *poFeature ) { OGRGeometry *poGeom = poFeature->GetGeometryRef(); OGRwkbGeometryType eGType = wkbNone; if( poGeom != nullptr ) { if( !poGeom->IsEmpty() ) { OGREnvelope sEnvelope; poGeom->getEnvelope(&sEnvelope); poDS->UpdateExtent(&sEnvelope); } eGType = wkbFlatten(poGeom->getGeometryType()); } if( eGType == wkbPoint ) { const char *pszBlockName = poFeature->GetFieldAsString("BlockName"); // We don't want to treat as a blocks ref if the block is not defined if( pszBlockName && poDS->oHeaderDS.LookupBlock(pszBlockName) == nullptr ) { if( poDS->poBlocksLayer == nullptr || poDS->poBlocksLayer->FindBlock(pszBlockName) == nullptr ) pszBlockName = nullptr; } if( pszBlockName != nullptr ) return WriteINSERT( poFeature ); else if( poFeature->GetStyleString() != nullptr && STARTS_WITH_CI(poFeature->GetStyleString(), "LABEL") ) return WriteTEXT( poFeature ); else return WritePOINT( poFeature ); } else if( eGType == wkbLineString || eGType == wkbMultiLineString ) return WritePOLYLINE( poFeature ); else if( eGType == wkbPolygon || eGType == wkbTriangle || eGType == wkbMultiPolygon) { if( bWriteHatch ) return WriteHATCH( poFeature ); else return WritePOLYLINE( poFeature ); } // Explode geometry collections into multiple entities. else if( eGType == wkbGeometryCollection ) { OGRGeometryCollection *poGC = poFeature->StealGeometry()->toGeometryCollection(); for( auto&& poMember: poGC ) { poFeature->SetGeometry( poMember ); OGRErr eErr = CreateFeature( poFeature ); if( eErr != OGRERR_NONE ) { delete poGC; return eErr; } } poFeature->SetGeometryDirectly( poGC ); return OGRERR_NONE; } else { CPLError( CE_Failure, CPLE_AppDefined, "No known way to write feature with geometry '%s'.", OGRGeometryTypeToName(eGType) ); return OGRERR_FAILURE; } }
OGRErr OGRDXFWriterLayer::ICreateFeature( OGRFeature *poFeature ) { OGRGeometry *poGeom = poFeature->GetGeometryRef(); OGRwkbGeometryType eGType = wkbNone; if( poGeom != NULL ) { if( !poGeom->IsEmpty() ) { OGREnvelope sEnvelope; poGeom->getEnvelope(&sEnvelope); poDS->UpdateExtent(&sEnvelope); } eGType = wkbFlatten(poGeom->getGeometryType()); } if( eGType == wkbPoint ) { const char *pszBlockName = poFeature->GetFieldAsString("BlockName"); // we don't want to treat as a block ref if we are writing blocks layer if( pszBlockName != NULL && poDS->poBlocksLayer != NULL && poFeature->GetDefnRef() == poDS->poBlocksLayer->GetLayerDefn()) pszBlockName = NULL; // We don't want to treat as a blocks ref if the block is not defined if( pszBlockName && poDS->oHeaderDS.LookupBlock(pszBlockName) == NULL ) { if( poDS->poBlocksLayer == NULL || poDS->poBlocksLayer->FindBlock(pszBlockName) == NULL ) pszBlockName = NULL; } if( pszBlockName != NULL ) return WriteINSERT( poFeature ); else if( poFeature->GetStyleString() != NULL && EQUALN(poFeature->GetStyleString(),"LABEL",5) ) return WriteTEXT( poFeature ); else return WritePOINT( poFeature ); } else if( eGType == wkbLineString || eGType == wkbMultiLineString ) return WritePOLYLINE( poFeature ); else if( eGType == wkbPolygon || eGType == wkbMultiPolygon ) { if( bWriteHatch ) return WriteHATCH( poFeature ); else return WritePOLYLINE( poFeature ); } // Explode geometry collections into multiple entities. else if( eGType == wkbGeometryCollection ) { OGRGeometryCollection *poGC = (OGRGeometryCollection *) poFeature->StealGeometry(); int iGeom; for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ ) { poFeature->SetGeometry( poGC->getGeometryRef(iGeom) ); OGRErr eErr = CreateFeature( poFeature ); if( eErr != OGRERR_NONE ) return eErr; } poFeature->SetGeometryDirectly( poGC ); return OGRERR_NONE; } else { CPLError( CE_Failure, CPLE_AppDefined, "No known way to write feature with geometry '%s'.", OGRGeometryTypeToName(eGType) ); return OGRERR_FAILURE; } }