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 c1a8ff687aba6bfcd523e0b72d15b7f0416bb693
Author: Peter Kovacs <[email protected]>
AuthorDate: Sun Jul 5 14:05:24 2026 +0200

    Adding Ellipse and spine support
    fixed negative-z extrusion arcs
---
 main/filter/source/graphicfilter/idxf/dxf2mtf.cxx  | 80 ++++++++++++++++++
 main/filter/source/graphicfilter/idxf/dxf2mtf.hxx  |  4 +
 main/filter/source/graphicfilter/idxf/dxfentrd.cxx | 94 ++++++++++++++++++++++
 main/filter/source/graphicfilter/idxf/dxfentrd.hxx | 51 +++++++++++-
 main/filter/source/graphicfilter/idxf/dxfreprd.cxx | 24 ++++++
 5 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx 
b/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx
index 477b2c1b0a..96ab298f1c 100644
--- a/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx
+++ b/main/filter/source/graphicfilter/idxf/dxf2mtf.cxx
@@ -737,6 +737,80 @@ void DXF2GDIMetaFile::DrawHatchEntity(const DXFHatchEntity 
& rE, const DXFTransf
        }
 }
 
+void DXF2GDIMetaFile::DrawEllipseEntity(const DXFEllipseEntity & rE, const 
DXFTransform & rTransform)
+{
+       if (SetLineAttribute(rE)==sal_False) return;
+
+       // Major axis vector (relative to centre) and the minor axis, which for 
the
+       // common planar case (extrusion 0,0,1) is ratio*(normal x major) =
+       // ratio*(-major.y, major.x, 0). A non-default extrusion is applied 
through
+       // rTransform by DrawEntities, so compute in the entity's own frame.
+       const DXFVector & aU = rE.aP1;
+       DXFVector aV(-aU.fy * rE.fRatio, aU.fx * rE.fRatio, 0.0);
+
+       double fSweep = rE.fEnd - rE.fStart;
+       while (fSweep <= 0.0)             fSweep += 2*3.14159265359;
+       while (fSweep >  2*3.14159265359) fSweep -= 2*3.14159265359;
+
+       sal_uInt16 nPoints = (sal_uInt16)( 
fSweep/(2*3.14159265359)*(double)OptPointsPerCircle + 0.5 );
+       if (nPoints<2) nPoints=2;
+
+       Polygon aPoly(nPoints);
+       for (sal_uInt16 i=0; i<nPoints; i++) {
+               double t = rE.fStart + fSweep*(double)i/(double)(nPoints-1);
+               rTransform.Transform( rE.aP0 + aU*cos(t) + aV*sin(t), aPoly[i] 
);
+       }
+       pVirDev->DrawPolyLine(aPoly);
+}
+
+
+void DXF2GDIMetaFile::DrawSplineEntity(const DXFSplineEntity & rE, const 
DXFTransform & rTransform)
+{
+       // Non-uniform B-spline, evaluated with de Boor's algorithm and drawn 
as a
+       // polyline. Rational (weighted) splines are treated as non-rational 
(the
+       // weights are ignored) — sufficient for the planar curves this targets.
+       if ( rE.pControlPts==NULL || rE.pfKnots==NULL ) return;
+       const long p = rE.nDegree;
+       const long n = rE.nCtrlCount - 1;
+       if ( p < 1 || n < p ) return;
+       if ( rE.nKnotCount != rE.nCtrlCount + p + 1 ) return;   // not a 
clamped B-spline
+       if ( SetLineAttribute(rE)==sal_False ) return;
+
+       const double * U = rE.pfKnots;
+       const double u0 = U[p];
+       const double u1 = U[n+1];
+       if ( u1 <= u0 ) return;
+
+       long nPoints = rE.nCtrlCount * 8;
+       if (nPoints < 2)    nPoints = 2;
+       if (nPoints > 2000) nPoints = 2000;
+
+       Polygon aPoly((sal_uInt16)nPoints);
+       DXFVector * d = new DXFVector[p+1];
+       for (long i=0; i<nPoints; i++) {
+               double u = u0 + (u1-u0)*(double)i/(double)(nPoints-1);
+               if (u >= u1) u = u1 - (u1-u0)*1e-9;   // stay inside the last 
knot span
+
+               // knot span k with U[k] <= u < U[k+1], clamped to [p, n]
+               long k = p;
+               while (k < n && u >= U[k+1]) k++;
+
+               long j, r;
+               for (j=0; j<=p; j++) d[j] = rE.pControlPts[k-p+j];
+               for (r=1; r<=p; r++) {
+                       for (j=p; j>=r; j--) {
+                               double fDenom = U[k+1+j-r] - U[k-p+j];
+                               double a = (fDenom!=0.0) ? (u - 
U[k-p+j])/fDenom : 0.0;
+                               d[j] = d[j-1]*(1.0-a) + d[j]*a;
+                       }
+               }
+               rTransform.Transform(d[p], aPoly[(sal_uInt16)i]);
+       }
+       delete[] d;
+       pVirDev->DrawPolyLine(aPoly);
+}
+
+
 void DXF2GDIMetaFile::Draw3DFaceEntity(const DXF3DFaceEntity & rE, const 
DXFTransform & rTransform)
 {
        sal_uInt16 nN,i;
@@ -848,6 +922,12 @@ void DXF2GDIMetaFile::DrawEntities(const DXFEntities & 
rEntities,
                        case DXF_HATCH :
                                DrawHatchEntity((DXFHatchEntity&)*pE, *pT);
                                break;
+                       case DXF_ELLIPSE:
+                               DrawEllipseEntity((DXFEllipseEntity&)*pE,*pT);
+                               break;
+                       case DXF_SPLINE:
+                               DrawSplineEntity((DXFSplineEntity&)*pE,*pT);
+                               break;
                        case DXF_3DFACE:
                                Draw3DFaceEntity((DXF3DFaceEntity&)*pE,*pT);
                                break;
diff --git a/main/filter/source/graphicfilter/idxf/dxf2mtf.hxx 
b/main/filter/source/graphicfilter/idxf/dxf2mtf.hxx
index a2578e6aed..1321581e25 100644
--- a/main/filter/source/graphicfilter/idxf/dxf2mtf.hxx
+++ b/main/filter/source/graphicfilter/idxf/dxf2mtf.hxx
@@ -105,6 +105,10 @@ private:
 
        void DrawHatchEntity( const DXFHatchEntity & rE, const DXFTransform & 
rTransform );
 
+       void DrawEllipseEntity( const DXFEllipseEntity & rE, const DXFTransform 
& rTransform );
+
+       void DrawSplineEntity( const DXFSplineEntity & rE, const DXFTransform & 
rTransform );
+
        void DrawEntities(const DXFEntities & rEntities,
                                          const DXFTransform & rTransform,
                                          sal_Bool bTopEntities);
diff --git a/main/filter/source/graphicfilter/idxf/dxfentrd.cxx 
b/main/filter/source/graphicfilter/idxf/dxfentrd.cxx
index e7cce8cc12..d3af99be5f 100644
--- a/main/filter/source/graphicfilter/idxf/dxfentrd.cxx
+++ b/main/filter/source/graphicfilter/idxf/dxfentrd.cxx
@@ -842,6 +842,98 @@ void DXFDimensionEntity::EvaluateGroup(DXFGroupReader & 
rDGR)
 
 //---------------------------- DXFEntites 
--------------------------------------
 
+//--------------------------DXFEllipseEntity------------------------------------
+
+DXFEllipseEntity::DXFEllipseEntity() : DXFBasicEntity(DXF_ELLIPSE)
+{
+       fRatio = 1.0;
+       fStart = 0.0;
+       fEnd   = 2*3.14159265359;
+}
+
+void DXFEllipseEntity::EvaluateGroup(DXFGroupReader & rDGR)
+{
+       switch (rDGR.GetG()) {
+               case 10: aP0.fx=rDGR.GetF(); break;
+               case 20: aP0.fy=rDGR.GetF(); break;
+               case 30: aP0.fz=rDGR.GetF(); break;
+               case 11: aP1.fx=rDGR.GetF(); break;
+               case 21: aP1.fy=rDGR.GetF(); break;
+               case 31: aP1.fz=rDGR.GetF(); break;
+               case 40: fRatio=rDGR.GetF(); break;
+               case 41: fStart=rDGR.GetF(); break;
+               case 42: fEnd=rDGR.GetF(); break;
+               default: DXFBasicEntity::EvaluateGroup(rDGR);
+       }
+}
+
+//--------------------------DXFSplineEntity-------------------------------------
+
+DXFSplineEntity::DXFSplineEntity() :
+       DXFBasicEntity(DXF_SPLINE),
+       nFlags(0),
+       nDegree(0),
+       nKnotCount(0),
+       nCtrlCount(0),
+       nFitCount(0),
+       pfKnots(NULL),
+       pControlPts(NULL),
+       nKnotIndex(0),
+       nCtrlIndex(0)
+{
+}
+
+DXFSplineEntity::~DXFSplineEntity()
+{
+       delete[] pfKnots;
+       delete[] pControlPts;
+}
+
+void DXFSplineEntity::EvaluateGroup(DXFGroupReader & rDGR)
+{
+       switch (rDGR.GetG()) {
+               case 70: nFlags  = rDGR.GetI(); break;
+               case 71: nDegree = rDGR.GetI(); break;
+               case 72:
+                       nKnotCount = rDGR.GetI();
+                       if ( rDGR.GetStatus() && nKnotCount > 0 ) {
+                               try { pfKnots = new double[nKnotCount]; }
+                               catch (::std::bad_alloc) { rDGR.SetError(); }
+                       }
+                       else if ( nKnotCount < 0 )
+                               rDGR.SetError();
+                       break;
+               case 73:
+                       nCtrlCount = rDGR.GetI();
+                       if ( rDGR.GetStatus() && nCtrlCount > 0 ) {
+                               try { pControlPts = new DXFVector[nCtrlCount]; }
+                               catch (::std::bad_alloc) { rDGR.SetError(); }
+                       }
+                       else if ( nCtrlCount < 0 )
+                               rDGR.SetError();
+                       break;
+               case 74: nFitCount = rDGR.GetI(); break;
+               case 40:
+                       if ( pfKnots && nKnotIndex < nKnotCount )
+                               pfKnots[nKnotIndex++] = rDGR.GetF();
+                       break;
+               // control points are 3D (10/20/30); advance on the Z group
+               case 10:
+                       if ( pControlPts && nCtrlIndex < nCtrlCount )
+                               pControlPts[nCtrlIndex].fx = rDGR.GetF();
+                       break;
+               case 20:
+                       if ( pControlPts && nCtrlIndex < nCtrlCount )
+                               pControlPts[nCtrlIndex].fy = rDGR.GetF();
+                       break;
+               case 30:
+                       if ( pControlPts && nCtrlIndex < nCtrlCount )
+                               pControlPts[nCtrlIndex++].fz = rDGR.GetF();
+                       break;
+               default: DXFBasicEntity::EvaluateGroup(rDGR);
+       }
+}
+
 void DXFEntities::Read(DXFGroupReader & rDGR)
 {
        DXFBasicEntity * pE, * * ppSucc;
@@ -874,6 +966,8 @@ void DXFEntities::Read(DXFGroupReader & rDGR)
                else if (strcmp(rDGR.GetS(),"3DFACE"    )==0) pE=new 
DXF3DFaceEntity;
                else if (strcmp(rDGR.GetS(),"DIMENSION" )==0) pE=new 
DXFDimensionEntity;
                else if (strcmp(rDGR.GetS(),"HATCH"             )==0) pE=new 
DXFHatchEntity;
+               else if (strcmp(rDGR.GetS(),"ELLIPSE"   )==0) pE=new 
DXFEllipseEntity;
+               else if (strcmp(rDGR.GetS(),"SPLINE"    )==0) pE=new 
DXFSplineEntity;
                else
                {
                        do {
diff --git a/main/filter/source/graphicfilter/idxf/dxfentrd.hxx 
b/main/filter/source/graphicfilter/idxf/dxfentrd.hxx
index 035082d72a..00475c0a9d 100644
--- a/main/filter/source/graphicfilter/idxf/dxfentrd.hxx
+++ b/main/filter/source/graphicfilter/idxf/dxfentrd.hxx
@@ -53,7 +53,9 @@ enum DXFEntityType {
        DXF_3DFACE,
        DXF_DIMENSION,
        DXF_LWPOLYLINE,
-       DXF_HATCH
+       DXF_HATCH,
+       DXF_ELLIPSE,
+       DXF_SPLINE
 };
 
 
//------------------------------------------------------------------------------
@@ -492,6 +494,53 @@ class DXFHatchEntity : public DXFBasicEntity
 };
 
 
+//--------------------------Ellipse---------------------------------------------
+
+class DXFEllipseEntity : public DXFBasicEntity {
+
+public:
+
+       DXFVector aP0;   // 10,20,30  center
+       DXFVector aP1;   // 11,21,31  endpoint of the major axis, relative to 
center
+       double fRatio;   // 40        ratio of minor axis to major axis
+       double fStart;   // 41        start parameter (radians; 0 for a full 
ellipse)
+       double fEnd;     // 42        end parameter   (radians; 2*pi for a full 
ellipse)
+
+       DXFEllipseEntity();
+
+protected:
+
+       virtual void EvaluateGroup(DXFGroupReader & rDGR);
+};
+
+//--------------------------Spline----------------------------------------------
+
+class DXFSplineEntity : public DXFBasicEntity {
+
+public:
+
+       long nFlags;         // 70   bit 1=closed, 2=periodic, 4=rational, 
8=planar
+       long nDegree;        // 71
+       long nKnotCount;     // 72
+       long nCtrlCount;     // 73
+       long nFitCount;      // 74
+
+       double *    pfKnots;      // 40        (nKnotCount entries)
+       DXFVector * pControlPts;  // 10,20,30  (nCtrlCount entries)
+
+       DXFSplineEntity();
+       ~DXFSplineEntity();
+
+protected:
+
+       virtual void EvaluateGroup(DXFGroupReader & rDGR);
+
+private:
+
+       long nKnotIndex;
+       long nCtrlIndex;
+};
+
 
//--------------------------Vertex----------------------------------------------
 
 class DXFVertexEntity : public DXFBasicEntity {
diff --git a/main/filter/source/graphicfilter/idxf/dxfreprd.cxx 
b/main/filter/source/graphicfilter/idxf/dxfreprd.cxx
index 3a1b1c44cf..6bcb2d49fd 100644
--- a/main/filter/source/graphicfilter/idxf/dxfreprd.cxx
+++ b/main/filter/source/graphicfilter/idxf/dxfreprd.cxx
@@ -496,6 +496,30 @@ void DXFRepresentation::CalcBoundingBox(const DXFEntities 
& rEntities,
                                }
                                break;
                        }
+                       case DXF_ELLIPSE: {
+                               // Conservative full-ellipse AABB (like ARC 
uses the full-circle
+                               // box): centre +/- the axis-projected radii. 
Over-approximates a
+                               // partial ellipse, which is fine for a 
bounding box.
+                               const DXFEllipseEntity * pE = 
(DXFEllipseEntity*)pBE;
+                               const DXFVector & aU = pE->aP1;
+                               DXFVector aV(-aU.fy*pE->fRatio, 
aU.fx*pE->fRatio, 0.0);
+                               double fRx = sqrt(aU.fx*aU.fx + aV.fx*aV.fx);
+                               double fRy = sqrt(aU.fy*aU.fy + aV.fy*aV.fy);
+                               DXFVector aC;
+                               aE2W.Transform(pE->aP0, aC);
+                               DXFVector aP=aC; aP.fx-=fRx; aP.fy-=fRy; 
rBox.Union(aP);
+                               aP=aC; aP.fx+=fRx; aP.fy+=fRy; rBox.Union(aP);
+                               break;
+                       }
+                       case DXF_SPLINE: {
+                               // The control polygon's convex hull contains 
the B-spline curve,
+                               // so unioning the control points bounds it 
(conservatively).
+                               const DXFSplineEntity * pE = 
(DXFSplineEntity*)pBE;
+                               if (pE->pControlPts != NULL)
+                                       for (long i = 0; i < pE->nCtrlCount; 
i++)
+                                               UnionOCS(rBox, aE2W, 
pE->pControlPts[i]);
+                               break;
+                       }
                }
                pBE=pBE->pSucc;
        }

Reply via email to