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; }
