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 b3f0e0e35baa62d68a57918931a5351dd240a868
Author: Peter Kovacs <[email protected]>
AuthorDate: Mon Jul 6 11:01:12 2026 +0200

    pattern hatches render as proper section lines instead of solid blobs
---
 main/filter/source/graphicfilter/idxf/dxf2mtf.cxx  | 205 +++++++++++++--------
 main/filter/source/graphicfilter/idxf/dxfentrd.cxx |  20 ++
 main/filter/source/graphicfilter/idxf/dxfentrd.hxx |  10 +
 3 files changed, 157 insertions(+), 78 deletions(-)

diff --git a/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx 
b/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx
index b116a54ae3..ac27b0a3cb 100644
--- a/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx
+++ b/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <vcl/gdimtf.hxx>
 #include <vcl/virdev.hxx>
+#include <vcl/hatch.hxx>
 #include <tools/poly.hxx>
 #include "dxf2mtf.hxx"
 
@@ -798,100 +799,148 @@ void DXF2GDIMetaFile::DrawLWPolyLineEntity(const 
DXFLWPolyLineEntity & rE, const
 
 void DXF2GDIMetaFile::DrawHatchEntity(const DXFHatchEntity & rE, const 
DXFTransform & rTransform )
 {
-       if ( rE.nBoundaryPathCount )
+       if ( !rE.nBoundaryPathCount )
+               return;
+
+       // Build the boundary as a PolyPolygon, tessellating curved edges so the
+       // area is measured correctly for both the solid fill and the pattern 
clip.
+       sal_Int32 j;
+       PolyPolygon aPolyPoly;
+       for ( j = 0; j < rE.nBoundaryPathCount; j++ )
        {
-               SetAreaAttribute( rE );
-               sal_Int32 j = 0;
-               PolyPolygon aPolyPoly;
-               for ( j = 0; j < rE.nBoundaryPathCount; j++ )
+               DXFPointArray aPtAry;
+               const DXFBoundaryPathData& rPathData = rE.pBoundaryPathData[ j 
];
+               if ( rPathData.bIsPolyLine )
                {
-                       DXFPointArray aPtAry;
-                       const DXFBoundaryPathData& rPathData = 
rE.pBoundaryPathData[ j ];
-                       if ( rPathData.bIsPolyLine )
+                       sal_Int32 i;
+                       for( i = 0; i < rPathData.nPointCount; i++ )
                        {
-                               sal_Int32 i;
-                               for( i = 0; i < rPathData.nPointCount; i++ )
-                               {
-                                       Point aPt;
-                                       rTransform.Transform( rPathData.pP[ i 
], aPt );
-                                       aPtAry.push_back( aPt );
-                               }
+                               Point aPt;
+                               rTransform.Transform( rPathData.pP[ i ], aPt );
+                               aPtAry.push_back( aPt );
                        }
-                       else
+               }
+               else
+               {
+                       sal_uInt32 i;
+                       for ( i = 0; i < rPathData.aEdges.size(); i++ )
                        {
-                               sal_uInt32 i;
-                               for ( i = 0; i < rPathData.aEdges.size(); i++ )
+                               const DXFEdgeType* pEdge = rPathData.aEdges[ i 
];
+                               switch( pEdge->nEdgeType )
                                {
-                                       const DXFEdgeType* pEdge = 
rPathData.aEdges[ i ];
-                                       switch( pEdge->nEdgeType )
+                                       case 1 :
+                                       {
+                                               Point aPt;
+                                               rTransform.Transform( 
((DXFEdgeTypeLine*)pEdge)->aStartPoint, aPt );
+                                               aPtAry.push_back( aPt );
+                                               rTransform.Transform( 
((DXFEdgeTypeLine*)pEdge)->aEndPoint, aPt );
+                                               aPtAry.push_back( aPt );
+                                       }
+                                       break;
+                                       case 2 :
                                        {
-                                               case 1 :
+                                               // Circular arc edge: sample 
the sweep and push the points.
+                                               // Angles are in degrees; 
direction follows the CCW flag.
+                                               const DXFEdgeTypeCircularArc* 
pArc = (const DXFEdgeTypeCircularArc*)pEdge;
+                                               double fSweep = pArc->fEndAngle 
- pArc->fStartAngle;
+                                               if ( 
pArc->nIsCounterClockwiseFlag )
+                                                       { while ( fSweep <= 0.0 
) fSweep += 360.0; }
+                                               else
+                                                       { while ( fSweep >= 0.0 
) fSweep -= 360.0; }
+                                               sal_uInt16 nPts = (sal_uInt16)( 
fabs(fSweep)/360.0*(double)OptPointsPerCircle + 0.5 );
+                                               if ( nPts < 2 ) nPts = 2;
+                                               for ( sal_uInt16 k = 0; k < 
nPts; k++ )
                                                {
+                                                       double a = ( 
pArc->fStartAngle + fSweep*(double)k/(double)(nPts-1) )
+                                                                               
* (3.14159265359/180.0);
                                                        Point aPt;
-                                                       rTransform.Transform( 
((DXFEdgeTypeLine*)pEdge)->aStartPoint, aPt );
-                                                       aPtAry.push_back( aPt );
-                                                       rTransform.Transform( 
((DXFEdgeTypeLine*)pEdge)->aEndPoint, aPt );
+                                                       rTransform.Transform(
+                                                               DXFVector( 
pArc->aCenter.fx + pArc->fRadius*cos(a),
+                                                                               
   pArc->aCenter.fy + pArc->fRadius*sin(a), 0.0 ), aPt );
                                                        aPtAry.push_back( aPt );
                                                }
-                                               break;
-                                               case 2 :
-                                               {
-/*
-                                                       double 
frx,fry,fA1,fdA,fAng;
-                                                       sal_uInt16 nPoints,i;
-                                                       DXFVector aC;
-                                                       Point aPS,aPE;
-                                                       
fA1=((DXFEdgeTypeCircularArc*)pEdge)->fStartAngle;
-                                                       
fdA=((DXFEdgeTypeCircularArc*)pEdge)->fEndAngle - fA1;
-                                                       while ( fdA >= 360.0 )
-                                                               fdA -= 360.0;
-                                                       while ( fdA <= 0 )
-                                                               fdA += 360.0;
-                                                       
rTransform.Transform(((DXFEdgeTypeCircularArc*)pEdge)->aCenter, aC);
-                                                       if ( fdA > 5.0 && 
rTransform.TransCircleToEllipse(((DXFEdgeTypeCircularArc*)pEdge)->fRadius,frx,fry
 ) == sal_True )
-                                                       {
-                                                               DXFVector 
aVS(cos(fA1/180.0*3.14159265359),sin(fA1/180.0*3.14159265359),0.0);
-                                                               
aVS*=((DXFEdgeTypeCircularArc*)pEdge)->fRadius;
-                                                               
aVS+=((DXFEdgeTypeCircularArc*)pEdge)->aCenter;
-                                                               DXFVector 
aVE(cos((fA1+fdA)/180.0*3.14159265359),sin((fA1+fdA)/180.0*3.14159265359),0.0);
-                                                               
aVE*=((DXFEdgeTypeCircularArc*)pEdge)->fRadius;
-                                                               
aVE+=((DXFEdgeTypeCircularArc*)pEdge)->aCenter;
-                                                               if ( 
rTransform.Mirror() == sal_True )
-                                                               {
-                                                                       
rTransform.Transform(aVS,aPS);
-                                                                       
rTransform.Transform(aVE,aPE);
-                                                               }
-                                                               else
-                                                               {
-                                                                       
rTransform.Transform(aVS,aPE);
-                                                                       
rTransform.Transform(aVE,aPS);
-                                                               }
-                                                               
pVirDev->DrawArc(
-                                                                       
Rectangle((long)(aC.fx-frx+0.5),(long)(aC.fy-fry+0.5),
-                                                                               
          (long)(aC.fx+frx+0.5),(long)(aC.fy+fry+0.5)),
-                                                                       aPS,aPE
-                                                               );
-                                                       }
-*/
-                                               }
-                                               break;
-                                               case 3 :
-                                               case 4 :
-                                               break;
                                        }
+                                       break;
+                                       case 3 :        // elliptical arc: not 
tessellated (not seen in
+                                       case 4 :        // practice here); 
spline edges store no control
+                                       break;          // points, so both fall 
through as before.
                                }
                        }
-                       sal_uInt16 i, nSize = (sal_uInt16)aPtAry.size();
-                       if ( nSize )
-                       {
-                               Polygon aPoly( nSize );
-                               for ( i = 0; i < nSize; i++ )
-                                       aPoly[ i ] = aPtAry[ i ];
-                               aPolyPoly.Insert( aPoly, POLYPOLY_APPEND );
-                       }
                }
-               if ( aPolyPoly.Count() )
+               sal_uInt16 i, nSize = (sal_uInt16)aPtAry.size();
+               if ( nSize )
+               {
+                       Polygon aPoly( nSize );
+                       for ( i = 0; i < nSize; i++ )
+                               aPoly[ i ] = aPtAry[ i ];
+                       aPolyPoly.Insert( aPoly, POLYPOLY_APPEND );
+               }
+       }
+       if ( !aPolyPoly.Count() )
+               return;
+
+       if ( rE.nFlags & 1 )
+       {
+               // Solid fill (group 70 bit 0): flood-fill the boundary in the 
entity colour.
+               SetAreaAttribute( rE );
+               pVirDev->DrawPolyPolygon( aPolyPoly );
+       }
+       else if ( rE.bHasPatternLine )
+       {
+               // Pattern fill: render the section lines with VCL's DrawHatch, 
which
+               // clips a line family to the boundary and records a 
MetaHatchAction.
+               // The DXF pattern is collapsed to a single/double/triple 
Hatch; the
+               // on-page angle and spacing come from mapping the 
pattern-definition
+               // line's direction and inter-line offset through rTransform, 
so any
+               // scale / rotation / block-insert nesting is accounted for.
+               long nColor = GetEntityColor( rE );
+               if ( nColor < 0 )
+                       return;
+               Color aColor = ConvertColor( (sal_uInt8)nColor );
+
+               const double fPi = 3.14159265359;
+               double fA = rE.fPatternLineAngle * (fPi/180.0);
+               DXFVector aDir, aOff;
+               rTransform.TransDir( DXFVector( cos(fA), sin(fA), 0.0 ), aDir );
+               rTransform.TransDir( DXFVector( rE.fPatternLineOffsetX, 
rE.fPatternLineOffsetY, 0.0 ), aOff );
+
+               double fDirLen = sqrt( aDir.fx*aDir.fx + aDir.fy*aDir.fy );
+               if ( fDirLen < 1e-9 )
+               {
+                       // degenerate direction: fall back to a bare outline 
(no blob).
+                       SetLineAttribute( rE );
                        pVirDev->DrawPolyPolygon( aPolyPoly );
+                       return;
+               }
+
+               // Perpendicular spacing between adjacent lines in device 
space, and the
+               // device line angle. VCL's angle is measured in the recorded 
coordinate
+               // system with its positive direction as (cos,-sin), hence 
-aDir.fy.
+               double fDist = fabs( aOff.fx*aDir.fy - aOff.fy*aDir.fx ) / 
fDirLen;
+               long nDistance = (long)( fDist + 0.5 );
+               if ( nDistance < 1 ) nDistance = 1;
+
+               double fAngle = atan2( -aDir.fy, aDir.fx ) * 1800.0 / fPi;
+               long nAngle10 = (long)( fAngle + (fAngle < 0.0 ? -0.5 : 0.5) );
+               nAngle10 %= 1800;
+               if ( nAngle10 < 0 )
+                       nAngle10 += 1800;
+
+               HatchStyle eStyle = HATCH_SINGLE;
+               if ( rE.nHatchPatternDefinitionLines == 2 )
+                       eStyle = HATCH_DOUBLE;
+               else if ( rE.nHatchPatternDefinitionLines >= 3 )
+                       eStyle = HATCH_TRIPLE;
+
+               Hatch aHatch( eStyle, aColor, nDistance, (sal_uInt16)nAngle10 );
+               pVirDev->DrawHatch( aPolyPoly, aHatch );
+       }
+       else
+       {
+               // Pattern fill but no pattern-definition line was parsed: 
stroke the
+               // boundary outline only (transparent fill), never a solid blob.
+               SetLineAttribute( rE );
+               pVirDev->DrawPolyPolygon( aPolyPoly );
        }
 }
 
diff --git a/main/filter/source/graphicfilter/idxf/dxfentrd.cxx 
b/main/filter/source/graphicfilter/idxf/dxfentrd.cxx
index 2b063fbe92..320b96c0f0 100644
--- a/main/filter/source/graphicfilter/idxf/dxfentrd.cxx
+++ b/main/filter/source/graphicfilter/idxf/dxfentrd.cxx
@@ -697,6 +697,7 @@ DXFHatchEntity::DXFHatchEntity() :
        DXFBasicEntity( DXF_HATCH ),
        bIsInBoundaryPathContext( sal_False ),
        nCurrentBoundaryPathIndex( -1 ),
+       bPatternLineOffsetSet( sal_False ),
        nFlags( 0 ),
        nAssociativityFlag( 0 ),
        nBoundaryPathCount( 0 ),
@@ -708,6 +709,10 @@ DXFHatchEntity::DXFHatchEntity() :
        nHatchPatternDefinitionLines( 0 ),
        fPixelSize( 1.0 ),
        nNumberOfSeedPoints( 0 ),
+       bHasPatternLine( sal_False ),
+       fPatternLineAngle( 0.0 ),
+       fPatternLineOffsetX( 0.0 ),
+       fPatternLineOffsetY( 0.0 ),
        pBoundaryPathData( NULL )
 {
 }
@@ -754,6 +759,21 @@ void DXFHatchEntity::EvaluateGroup( DXFGroupReader & rDGR )
                case 47 : fPixelSize = rDGR.GetF(); break;
                case 98 : nNumberOfSeedPoints = rDGR.GetI(); break;
 
+               // Pattern-definition lines (only present for a pattern fill, 
after 75).
+               // Capture the FIRST line's angle (53) and inter-line offset 
(45/46);
+               // 53/45/46 appear nowhere else in a HATCH, so intercepting 
them here is
+               // safe. Codes 43/44 (base point) are not needed for a VCL 
Hatch.
+               case 53 :
+                       if ( !bHasPatternLine ) { fPatternLineAngle = 
rDGR.GetF(); bHasPatternLine = sal_True; }
+                       break;
+               case 45 :
+                       if ( bHasPatternLine && !bPatternLineOffsetSet ) 
fPatternLineOffsetX = rDGR.GetF();
+                       break;
+               case 46 :
+                       if ( bHasPatternLine && !bPatternLineOffsetSet )
+                       { fPatternLineOffsetY = rDGR.GetF(); 
bPatternLineOffsetSet = sal_True; }
+                       break;
+
                //!! passthrough !!
                case 92 : nCurrentBoundaryPathIndex++;
                default:
diff --git a/main/filter/source/graphicfilter/idxf/dxfentrd.hxx 
b/main/filter/source/graphicfilter/idxf/dxfentrd.hxx
index 62f1724f05..3c08f08a39 100644
--- a/main/filter/source/graphicfilter/idxf/dxfentrd.hxx
+++ b/main/filter/source/graphicfilter/idxf/dxfentrd.hxx
@@ -468,6 +468,7 @@ class DXFHatchEntity : public DXFBasicEntity
 {
                sal_Bool        bIsInBoundaryPathContext;
                sal_Int32       nCurrentBoundaryPathIndex;
+               sal_Bool        bPatternLineOffsetSet;                  // 
transient parse state (first 45/46 captured)
 
        public :
 
@@ -484,6 +485,15 @@ class DXFHatchEntity : public DXFBasicEntity
                double          fPixelSize;                                     
        // 47
                sal_Int32       nNumberOfSeedPoints;                    // 98
 
+               // First pattern-definition line (78 block). Enough to drive a 
VCL Hatch
+               // (single/double/triple): the line angle (53) and the 
inter-line offset
+               // (45/46) give on-page angle + spacing; multi-line patterns 
collapse to
+               // this line's geometry plus the style from 
nHatchPatternDefinitionLines.
+               sal_Bool        bHasPatternLine;                                
// a 53 line angle was parsed
+               double          fPatternLineAngle;                              
// 53
+               double          fPatternLineOffsetX;                    // 45
+               double          fPatternLineOffsetY;                    // 46
+
                DXFBoundaryPathData* pBoundaryPathData;
 
                DXFHatchEntity();

Reply via email to