This is an automated email from the ASF dual-hosted git repository. leginee pushed a commit to branch bugfix-dxf-filter in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 5a471cc654e6d0c8e4aa8ee2e8e7afc22de0a742 Author: Peter Kovacs <[email protected]> AuthorDate: Sun Jul 5 22:49:30 2026 +0200 support LWPOLYLINE bulge (group 42) --- main/filter/source/graphicfilter/idxf/dxf2mtf.cxx | 76 ++++++++++++++++++---- main/filter/source/graphicfilter/idxf/dxfentrd.cxx | 15 ++++- main/filter/source/graphicfilter/idxf/dxfentrd.hxx | 1 + 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx b/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx index 658a6520f3..cebe0b6cd1 100644 --- a/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx +++ b/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx @@ -594,8 +594,8 @@ void DXF2GDIMetaFile::DrawPolyLineEntity(const DXFPolyLineEntity & rE, const DXF void DXF2GDIMetaFile::DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE, const DXFTransform & rTransform ) { - const sal_Int32 nPolySize = rE.nCount; - if ( nPolySize <= 0 || rE.pP == NULL ) + const sal_Int32 nVtxCount = rE.nCount; + if ( nVtxCount <= 0 || rE.pP == NULL ) return; double fW = rE.fConstantWidth; @@ -604,12 +604,66 @@ void DXF2GDIMetaFile::DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE, const const sal_Bool bClosed = ( rE.nFlags & 1 ) != 0; + // Build the outline in device space, expanding any segment that carries a + // non-zero bulge into an arc. In DXF a bulge is tan(sweep/4), so bulge 1.0 + // is a 180 degree arc; a circle is commonly stored as two bulged segments + // (e.g. Eagle CAD). Straight segments (bulge 0) contribute just the vertex. + DXFPointArray aPtAry; + Point aPt; + for ( sal_Int32 i = 0; i < nVtxCount; i++ ) + { + rTransform.Transform( rE.pP[ i ], aPt ); + aPtAry.push_back( aPt ); + + sal_Int32 iNext = i + 1; + if ( iNext >= nVtxCount ) + { + if ( !bClosed ) break; // open: no segment after the last vertex + iNext = 0; // closed: last vertex arcs back to the first + } + + const double fBulge = ( rE.pBulge != NULL ) ? rE.pBulge[ i ] : 0.0; + if ( fBulge != 0.0 ) + { + const DXFVector & rS = rE.pP[ i ]; + const DXFVector & rEnd = rE.pP[ iNext ]; + // Arc centre from the bulge (cotangent form): the centre lies on the + // chord's perpendicular bisector, offset by cot(sweep/2)/2 * chord. + const double fCot = 0.5 * ( 1.0 / fBulge - fBulge ); + const double fCx = 0.5 * ( ( rS.fx + rEnd.fx ) + fCot * ( rS.fy - rEnd.fy ) ); + const double fCy = 0.5 * ( ( rS.fy + rEnd.fy ) + fCot * ( rEnd.fx - rS.fx ) ); + const double fRx = rS.fx - fCx; + const double fRy = rS.fy - fCy; + const double fRadius = sqrt( fRx * fRx + fRy * fRy ); + const double fStartAng = atan2( fRy, fRx ); + const double fSweep = 4.0 * atan( fBulge ); // signed: >0 = CCW + sal_Int32 nArcPoints = (sal_Int32)( fabs( fSweep ) / ( 2 * 3.14159265359 ) + * (double)OptPointsPerCircle + 0.5 ); + // Emit the interior arc samples; the start vertex is already pushed + // and the end vertex is pushed as the next loop's leading vertex. + for ( sal_Int32 k = 1; k < nArcPoints; k++ ) + { + const double fAng = fStartAng + fSweep * (double)k / (double)nArcPoints; + rTransform.Transform( + DXFVector( fCx + fRadius * cos( fAng ), + fCy + fRadius * sin( fAng ), + rS.fz ), + aPt ); + aPtAry.push_back( aPt ); + } + } + } + + const sal_Int32 nPolySize = (sal_Int32)aPtAry.size(); + if ( nPolySize < 2 ) + return; + if ( nPolySize <= 0xFFFF ) { // Fits in a single tools Polygon (which is indexed by sal_uInt16). Polygon aPoly( (sal_uInt16)nPolySize ); for ( sal_Int32 i = 0; i < nPolySize; i++ ) - rTransform.Transform( rE.pP[ i ], aPoly[ (sal_uInt16)i ] ); + aPoly[ (sal_uInt16)i ] = aPtAry[ i ]; if ( bClosed ) pVirDev->DrawPolygon( aPoly ); else @@ -617,11 +671,9 @@ void DXF2GDIMetaFile::DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE, const return; } - // The DXF vertex count (group code 90) is a 32-bit value, but a tools Polygon - // holds at most 0xFFFF points. Render a larger polyline as a sequence of - // Polygon segments that overlap by one point, so the whole line is drawn - // without truncation and the stroke stays continuous. The source array pP is - // walked with the full 32-bit position; only the per-segment index is 16-bit. + // The tessellated outline can exceed the 0xFFFF points a tools Polygon holds. + // Render it as a sequence of Polygon segments that overlap by one point, so + // the whole line is drawn without truncation and the stroke stays continuous. const sal_Int32 nMaxChunk = 0xFFFF; sal_Int32 nStart = 0; while ( nStart + 1 < nPolySize ) @@ -632,16 +684,16 @@ void DXF2GDIMetaFile::DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE, const const sal_uInt16 nChunk = (sal_uInt16)( nEnd - nStart ); Polygon aChunk( nChunk ); for ( sal_uInt16 j = 0; j < nChunk; j++ ) - rTransform.Transform( rE.pP[ nStart + j ], aChunk[ j ] ); + aChunk[ j ] = aPtAry[ nStart + j ]; pVirDev->DrawPolyLine( aChunk ); nStart = nEnd - 1; // next segment shares this segment's last point } if ( bClosed ) { - // Close the outline: last vertex back to the first. + // Close the outline: last point back to the first. Polygon aClose( 2 ); - rTransform.Transform( rE.pP[ nPolySize - 1 ], aClose[ 0 ] ); - rTransform.Transform( rE.pP[ 0 ], aClose[ 1 ] ); + aClose[ 0 ] = aPtAry[ nPolySize - 1 ]; + aClose[ 1 ] = aPtAry[ 0 ]; pVirDev->DrawPolyLine( aClose ); } } diff --git a/main/filter/source/graphicfilter/idxf/dxfentrd.cxx b/main/filter/source/graphicfilter/idxf/dxfentrd.cxx index d3af99be5f..e7c8e23671 100644 --- a/main/filter/source/graphicfilter/idxf/dxfentrd.cxx +++ b/main/filter/source/graphicfilter/idxf/dxfentrd.cxx @@ -422,7 +422,8 @@ DXFLWPolyLineEntity::DXFLWPolyLineEntity() : fConstantWidth( 0.0 ), fStartWidth( 0.0 ), fEndWidth( 0.0 ), - pP( NULL ) + pP( NULL ), + pBulge( NULL ) { } @@ -438,6 +439,9 @@ void DXFLWPolyLineEntity::EvaluateGroup( DXFGroupReader & rDGR ) try { pP = new DXFVector[ nCount ]; + pBulge = new double[ nCount ]; + for ( sal_Int32 i = 0; i < nCount; i++ ) + pBulge[ i ] = 0.0; } catch (::std::bad_alloc) { @@ -464,6 +468,14 @@ void DXFLWPolyLineEntity::EvaluateGroup( DXFGroupReader & rDGR ) pP[ nIndex++ ].fy = rDGR.GetF(); } break; + case 42: + { + // per-vertex bulge; follows the 10/20 pair of the vertex it + // belongs to (nIndex has already advanced past that vertex). + if ( pBulge && ( nIndex > 0 ) && ( nIndex <= nCount ) ) + pBulge[ nIndex - 1 ] = rDGR.GetF(); + } + break; default: DXFBasicEntity::EvaluateGroup(rDGR); } } @@ -471,6 +483,7 @@ void DXFLWPolyLineEntity::EvaluateGroup( DXFGroupReader & rDGR ) DXFLWPolyLineEntity::~DXFLWPolyLineEntity() { delete[] pP; + delete[] pBulge; } //--------------------------DXFHatchEntity------------------------------------- diff --git a/main/filter/source/graphicfilter/idxf/dxfentrd.hxx b/main/filter/source/graphicfilter/idxf/dxfentrd.hxx index 00475c0a9d..3f1c57a2d8 100644 --- a/main/filter/source/graphicfilter/idxf/dxfentrd.hxx +++ b/main/filter/source/graphicfilter/idxf/dxfentrd.hxx @@ -371,6 +371,7 @@ class DXFLWPolyLineEntity : public DXFBasicEntity double fEndWidth; // 41 DXFVector* pP; + double* pBulge; // 42 (per vertex; parallel to pP, 0.0 = straight segment) DXFLWPolyLineEntity(); ~DXFLWPolyLineEntity();
