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();

Reply via email to