1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26
27 #include <string.h>
28 #include <vcl/gdimtf.hxx>
29 #include <vcl/virdev.hxx>
30 #include <vcl/hatch.hxx>
31 #include <tools/poly.hxx>
32 #include "dxf2mtf.hxx"
33
34 #include <math.h>
35
36
CountEntities(const DXFEntities & rEntities)37 sal_uLong DXF2GDIMetaFile::CountEntities(const DXFEntities & rEntities)
38 {
39 const DXFBasicEntity * pBE;
40 sal_uLong nRes;
41
42 nRes=0;
43 for (pBE=rEntities.pFirst; pBE!=NULL; pBE=pBE->pSucc) nRes++;
44 return nRes;
45 }
46
47
MayCallback(sal_uLong)48 void DXF2GDIMetaFile::MayCallback(sal_uLong /*nMainEntitiesProcessed*/)
49 {
50 // sal_uLong nPercent;
51 /*
52 if (pCallback!=NULL && nMainEntitiesCount!=0) {
53 nPercent=nMinPercent+(nMaxPercent-nMinPercent)*nMainEntitiesProcessed/nMainEntitiesCount;
54 if (nPercent>=nLastPercent+4) {
55 if (((*pCallback)(pCallerData,(sal_uInt16)nPercent))==sal_True) bStatus=sal_False;
56 nLastPercent=nPercent;
57 }
58 }
59 */
60 }
61
ConvertColor(sal_uInt8 nColor)62 Color DXF2GDIMetaFile::ConvertColor(sal_uInt8 nColor)
63 {
64 return Color(
65 pDXF->aPalette.GetRed( nColor ),
66 pDXF->aPalette.GetGreen( nColor ),
67 pDXF->aPalette.GetBlue( nColor ) );
68 }
69
GetEntityColor(const DXFBasicEntity & rE)70 long DXF2GDIMetaFile::GetEntityColor(const DXFBasicEntity & rE)
71 {
72 long nColor;
73 const DXFLayer * pLayer;
74
75 nColor=rE.nColor;
76 if (nColor==256) {
77 if (rE.sLayer[0]=='0' && rE.sLayer[1]==0) nColor=nParentLayerColor;
78 else {
79 pLayer=pDXF->aTables.SearchLayer(rE.sLayer);
80 if (pLayer!=NULL) nColor=pLayer->nColor;
81 else nColor=nParentLayerColor;
82 }
83 }
84 else if (nColor==0) nColor=nBlockColor;
85 return nColor;
86 }
87
LTypeToDXFLineInfo(const char * sLineType)88 DXFLineInfo DXF2GDIMetaFile::LTypeToDXFLineInfo(const char * sLineType)
89 {
90 const DXFLType * pLT;
91 DXFLineInfo aDXFLineInfo;
92
93 pLT=pDXF->aTables.SearchLType(sLineType);
94 if (pLT==NULL || pLT->nDashCount == 0) {
95 aDXFLineInfo.eStyle = LINE_SOLID;
96 }
97 else {
98 sal_Int32 i;
99 double x;
100 aDXFLineInfo.eStyle = LINE_DASH;
101 for (i=0; i < (pLT->nDashCount); i++) {
102 x = pLT->fDash[i] * pDXF->getGlobalLineTypeScale();
103 // ####
104 // x = (sal_Int32) rTransform.TransLineWidth( pLT->fDash[i] * pDXF->getGlobalLineTypeScale() );
105 if ( x >= 0.0 ) {
106 if ( aDXFLineInfo.nDotCount == 0 ) {
107 aDXFLineInfo.nDotCount ++;
108 aDXFLineInfo.fDotLen = x;
109 }
110 else if ( aDXFLineInfo.fDotLen == x ) {
111 aDXFLineInfo.nDotCount ++;
112 }
113 else if ( aDXFLineInfo.nDashCount == 0 ) {
114 aDXFLineInfo.nDashCount ++;
115 aDXFLineInfo.fDashLen = x;
116 }
117 else if ( aDXFLineInfo.fDashLen == x ) {
118 aDXFLineInfo.nDashCount ++;
119 }
120 else {
121 // It is impossible to be converted.
122 }
123 }
124 else {
125 if ( aDXFLineInfo.fDistance == 0 ) {
126 aDXFLineInfo.fDistance = -1 * x;
127 }
128 else {
129 // It is impossible to be converted.
130 }
131 }
132
133 }
134 }
135
136 // A DXF pattern element of exactly 0.0 is a *dot* (a point), distinct from a
137 // positive-length dash (e.g. DOT2 = 0,-3.175). AutoCAD paints it as a small
138 // dot, but VCL has no round dot: LineInfo strokes every "on" run as a short
139 // segment, so a dot is just a very short dash. Rendered verbatim the length
140 // collapses to a sub-unit mark (Transform() only clamps it to 1/100mm) and the
141 // line came out invisible (issue 70275). Give a zero-length dot/dash a small
142 // model-unit length so it survives scaling; keep it a SMALL fraction of the
143 // gap (0.05) so it reads as a dot, not a dash. Done here in model units, not
144 // after scaling, so it tracks the drawing size. Only true 0.0 elements are
145 // adjusted — real authored dashes keep their length.
146 const double fDotOnFraction = 0.05; // dot mark length as a fraction of the gap
147 if (aDXFLineInfo.fDistance != 0.0) {
148 if (aDXFLineInfo.nDotCount > 0 && aDXFLineInfo.fDotLen == 0.0)
149 aDXFLineInfo.fDotLen = aDXFLineInfo.fDistance * fDotOnFraction;
150 if (aDXFLineInfo.nDashCount > 0 && aDXFLineInfo.fDashLen == 0.0)
151 aDXFLineInfo.fDashLen = aDXFLineInfo.fDistance * fDotOnFraction;
152 }
153
154 return aDXFLineInfo;
155 }
156
GetEntityDXFLineInfo(const DXFBasicEntity & rE)157 DXFLineInfo DXF2GDIMetaFile::GetEntityDXFLineInfo(const DXFBasicEntity & rE)
158 {
159 DXFLineInfo aDXFLineInfo;
160 const DXFLayer * pLayer;
161
162 aDXFLineInfo.eStyle = LINE_SOLID;
163 aDXFLineInfo.fWidth = 0;
164 aDXFLineInfo.nDashCount = 0;
165 aDXFLineInfo.fDashLen = 0;
166 aDXFLineInfo.nDotCount = 0;
167 aDXFLineInfo.fDotLen = 0;
168 aDXFLineInfo.fDistance = 0;
169
170 if (strcmp(rE.sLineType,"BYLAYER")==0) {
171 if (rE.sLayer[0]=='0' && rE.sLayer[1]==0) aDXFLineInfo=aParentLayerDXFLineInfo;
172 else {
173 pLayer=pDXF->aTables.SearchLayer(rE.sLayer);
174 if (pLayer!=NULL) aDXFLineInfo=LTypeToDXFLineInfo(pLayer->sLineType);
175 else aDXFLineInfo=aParentLayerDXFLineInfo;
176 }
177 }
178 else if (strcmp(rE.sLineType,"BYBLOCK")==0) {
179 aDXFLineInfo=aBlockDXFLineInfo;
180 }
181 else aDXFLineInfo=LTypeToDXFLineInfo(rE.sLineType);
182 return aDXFLineInfo;
183 }
184
185
SetLineAttribute(const DXFBasicEntity & rE,sal_uLong)186 sal_Bool DXF2GDIMetaFile::SetLineAttribute(const DXFBasicEntity & rE, sal_uLong /*nWidth*/)
187 {
188 long nColor;
189 Color aColor;
190
191 nColor=GetEntityColor(rE);
192 if (nColor<0) return sal_False;
193 aColor=ConvertColor((sal_uInt8)nColor);
194
195 if (aActLineColor!=aColor) {
196 pVirDev->SetLineColor( aActLineColor = aColor );
197 }
198
199 if (aActFillColor!=Color( COL_TRANSPARENT )) {
200 pVirDev->SetFillColor(aActFillColor = Color( COL_TRANSPARENT ));
201 }
202 return sal_True;
203 }
204
205
SetAreaAttribute(const DXFBasicEntity & rE)206 sal_Bool DXF2GDIMetaFile::SetAreaAttribute(const DXFBasicEntity & rE)
207 {
208 long nColor;
209 Color aColor;
210
211 nColor=GetEntityColor(rE);
212 if (nColor<0) return sal_False;
213 aColor=ConvertColor((sal_uInt8)nColor);
214
215 if (aActLineColor!=aColor) {
216 pVirDev->SetLineColor( aActLineColor = aColor );
217 }
218
219 if ( aActFillColor == Color( COL_TRANSPARENT ) || aActFillColor != aColor) {
220 pVirDev->SetFillColor( aActFillColor = aColor );
221 }
222 return sal_True;
223 }
224
225
SetFontAttribute(const DXFBasicEntity & rE,short nAngle,sal_uInt16 nHeight,double)226 sal_Bool DXF2GDIMetaFile::SetFontAttribute(const DXFBasicEntity & rE, short nAngle, sal_uInt16 nHeight, double /*fWidthScale*/)
227 {
228 long nColor;
229 Color aColor;
230 Font aFont;
231
232 nAngle=-nAngle;
233 while (nAngle>3600) nAngle-=3600;
234 while (nAngle<0) nAngle+=3600;
235
236 nColor=GetEntityColor(rE);
237 if (nColor<0) return sal_False;
238 aColor=ConvertColor((sal_uInt8)nColor);
239
240 aFont.SetColor(aColor);
241 aFont.SetTransparent(sal_True);
242 aFont.SetFamily(FAMILY_SWISS);
243 aFont.SetSize(Size(0,nHeight));
244 aFont.SetAlign(ALIGN_BASELINE);
245 aFont.SetOrientation(nAngle);
246 if (aActFont!=aFont) {
247 aActFont=aFont;
248 pVirDev->SetFont(aActFont);
249 }
250
251 return sal_True;
252 }
253
254
DrawLineEntity(const DXFLineEntity & rE,const DXFTransform & rTransform)255 void DXF2GDIMetaFile::DrawLineEntity(const DXFLineEntity & rE, const DXFTransform & rTransform)
256 {
257 if (SetLineAttribute(rE)) {
258 Point aP0,aP1;
259 rTransform.Transform(rE.aP0,aP0);
260 rTransform.Transform(rE.aP1,aP1);
261
262 DXFLineInfo aDXFLineInfo;
263 aDXFLineInfo=GetEntityDXFLineInfo(rE);
264 LineInfo aLineInfo;
265 aLineInfo = rTransform.Transform(aDXFLineInfo);
266
267 #if 0
268 printf("%f\n", rTransform.TransLineWidth(1000.0));
269
270 // LINE_NONE = 0, LINE_SOLID = 1, LINE_DASH = 2, LineStyle_FORCE_EQUAL_SIZE = SAL_MAX_ENUM
271 aLineInfo.SetStyle( LINE_DASH );
272 aLineInfo.SetWidth( 300 );
273 aLineInfo.SetDashCount( 2 );
274 aLineInfo.SetDashLen( 100 );
275 aLineInfo.SetDotCount( 1 );
276 aLineInfo.SetDotLen( 0 );
277 aLineInfo.SetDistance( 500 );
278 #endif
279
280 pVirDev->DrawLine(aP0,aP1,aLineInfo);
281 if (rE.fThickness!=0) {
282 Point aP2,aP3;
283 rTransform.Transform(rE.aP0+DXFVector(0,0,rE.fThickness),aP2);
284 rTransform.Transform(rE.aP1+DXFVector(0,0,rE.fThickness),aP3);
285 pVirDev->DrawLine(aP2,aP3);
286 pVirDev->DrawLine(aP0,aP2);
287 pVirDev->DrawLine(aP1,aP3);
288 }
289 }
290 }
291
292
DrawPointEntity(const DXFPointEntity & rE,const DXFTransform & rTransform)293 void DXF2GDIMetaFile::DrawPointEntity(const DXFPointEntity & rE, const DXFTransform & rTransform)
294 {
295
296 if (SetLineAttribute(rE)) {
297 Point aP0;
298 rTransform.Transform(rE.aP0,aP0);
299 if (rE.fThickness==0) pVirDev->DrawPixel(aP0);
300 else {
301 Point aP1;
302 rTransform.Transform(rE.aP0+DXFVector(0,0,rE.fThickness),aP1);
303 pVirDev->DrawLine(aP0,aP1);
304 }
305 }
306 }
307
308
DrawCircleEntity(const DXFCircleEntity & rE,const DXFTransform & rTransform)309 void DXF2GDIMetaFile::DrawCircleEntity(const DXFCircleEntity & rE, const DXFTransform & rTransform)
310 {
311 double frx,fry,fAng;
312 sal_uInt16 nPoints,i;
313 DXFVector aC;
314
315 if (SetLineAttribute(rE)==sal_False) return;
316 rTransform.Transform(rE.aP0,aC);
317 if (rE.fThickness==0 && rTransform.TransCircleToEllipse(rE.fRadius,frx,fry)==sal_True) {
318 pVirDev->DrawEllipse(
319 Rectangle((long)(aC.fx-frx+0.5),(long)(aC.fy-fry+0.5),
320 (long)(aC.fx+frx+0.5),(long)(aC.fy+fry+0.5)));
321 }
322 else {
323 nPoints=OptPointsPerCircle;
324 Polygon aPoly(nPoints);
325 for (i=0; i<nPoints; i++) {
326 fAng=2*3.14159265359/(double)(nPoints-1)*(double)i;
327 rTransform.Transform(
328 rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),0),
329 aPoly[i]
330 );
331 }
332 pVirDev->DrawPolyLine(aPoly);
333 if (rE.fThickness!=0) {
334 Polygon aPoly2(nPoints);
335 for (i=0; i<nPoints; i++) {
336 fAng=2*3.14159265359/(double)(nPoints-1)*(double)i;
337 rTransform.Transform(
338 rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),rE.fThickness),
339 aPoly2[i]
340 );
341
342 }
343 pVirDev->DrawPolyLine(aPoly2);
344 for (i=0; i<nPoints-1; i++) pVirDev->DrawLine(aPoly[i],aPoly2[i]);
345 }
346 }
347 }
348
349
DrawArcEntity(const DXFArcEntity & rE,const DXFTransform & rTransform)350 void DXF2GDIMetaFile::DrawArcEntity(const DXFArcEntity & rE, const DXFTransform & rTransform)
351 {
352 double frx,fry,fA1,fdA,fAng;
353 sal_uInt16 nPoints,i;
354 DXFVector aC;
355 Point aPS,aPE;
356
357 if (SetLineAttribute(rE)==sal_False) return;
358 fA1=rE.fStart;
359 fdA=rE.fEnd-fA1;
360 while (fdA>=360.0) fdA-=360.0;
361 while (fdA<=0) fdA+=360.0;
362 rTransform.Transform(rE.aP0,aC);
363 if (rE.fThickness==0 && fdA>5.0 && rTransform.TransCircleToEllipse(rE.fRadius,frx,fry)==sal_True) {
364 DXFVector aVS(cos(fA1/180.0*3.14159265359),sin(fA1/180.0*3.14159265359),0.0);
365 aVS*=rE.fRadius;
366 aVS+=rE.aP0;
367 DXFVector aVE(cos((fA1+fdA)/180.0*3.14159265359),sin((fA1+fdA)/180.0*3.14159265359),0.0);
368 aVE*=rE.fRadius;
369 aVE+=rE.aP0;
370 if (rTransform.Mirror()==sal_True) {
371 rTransform.Transform(aVS,aPS);
372 rTransform.Transform(aVE,aPE);
373 }
374 else {
375 rTransform.Transform(aVS,aPE);
376 rTransform.Transform(aVE,aPS);
377 }
378 pVirDev->DrawArc(
379 Rectangle((long)(aC.fx-frx+0.5),(long)(aC.fy-fry+0.5),
380 (long)(aC.fx+frx+0.5),(long)(aC.fy+fry+0.5)),
381 aPS,aPE
382 );
383 }
384 else {
385 nPoints=(sal_uInt16)(fdA/360.0*(double)OptPointsPerCircle+0.5);
386 if (nPoints<2) nPoints=2;
387 Polygon aPoly(nPoints);
388 for (i=0; i<nPoints; i++) {
389 fAng=3.14159265359/180.0 * ( fA1 + fdA/(double)(nPoints-1)*(double)i );
390 rTransform.Transform(
391 rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),0),
392 aPoly[i]
393 );
394 }
395 pVirDev->DrawPolyLine(aPoly);
396 if (rE.fThickness!=0) {
397 Polygon aPoly2(nPoints);
398 for (i=0; i<nPoints; i++) {
399 fAng=3.14159265359/180.0 * ( fA1 + fdA/(double)(nPoints-1)*(double)i );
400 rTransform.Transform(
401 rE.aP0+DXFVector(rE.fRadius*cos(fAng),rE.fRadius*sin(fAng),rE.fThickness),
402 aPoly2[i]
403 );
404 }
405 pVirDev->DrawPolyLine(aPoly2);
406 for (i=0; i<nPoints; i++) pVirDev->DrawLine(aPoly[i],aPoly2[i]);
407 }
408 }
409 }
410
411
DrawTraceEntity(const DXFTraceEntity & rE,const DXFTransform & rTransform)412 void DXF2GDIMetaFile::DrawTraceEntity(const DXFTraceEntity & rE, const DXFTransform & rTransform)
413 {
414 if (SetLineAttribute(rE)) {
415 Polygon aPoly(4);
416 rTransform.Transform(rE.aP0,aPoly[0]);
417 rTransform.Transform(rE.aP1,aPoly[1]);
418 rTransform.Transform(rE.aP3,aPoly[2]);
419 rTransform.Transform(rE.aP2,aPoly[3]);
420 pVirDev->DrawPolygon(aPoly);
421 if (rE.fThickness!=0) {
422 sal_uInt16 i;
423 Polygon aPoly2(4);
424 DXFVector aVAdd(0,0,rE.fThickness);
425 rTransform.Transform(rE.aP0+aVAdd,aPoly2[0]);
426 rTransform.Transform(rE.aP1+aVAdd,aPoly2[1]);
427 rTransform.Transform(rE.aP3+aVAdd,aPoly2[2]);
428 rTransform.Transform(rE.aP2+aVAdd,aPoly2[3]);
429 pVirDev->DrawPolygon(aPoly2);
430 for (i=0; i<4; i++) pVirDev->DrawLine(aPoly[i],aPoly2[i]);
431 }
432 }
433 }
434
435
DrawSolidEntity(const DXFSolidEntity & rE,const DXFTransform & rTransform)436 void DXF2GDIMetaFile::DrawSolidEntity(const DXFSolidEntity & rE, const DXFTransform & rTransform)
437 {
438 if (SetAreaAttribute(rE)) {
439 sal_uInt16 nN;
440 if (rE.aP2==rE.aP3) nN=3; else nN=4;
441 Polygon aPoly(nN);
442 rTransform.Transform(rE.aP0,aPoly[0]);
443 rTransform.Transform(rE.aP1,aPoly[1]);
444 rTransform.Transform(rE.aP3,aPoly[2]);
445 if (nN>3) rTransform.Transform(rE.aP2,aPoly[3]);
446 pVirDev->DrawPolygon(aPoly);
447 if (rE.fThickness!=0) {
448 Polygon aPoly2(nN);
449 DXFVector aVAdd(0,0,rE.fThickness);
450 rTransform.Transform(rE.aP0+aVAdd,aPoly2[0]);
451 rTransform.Transform(rE.aP1+aVAdd,aPoly2[1]);
452 rTransform.Transform(rE.aP3+aVAdd,aPoly2[2]);
453 if (nN>3) rTransform.Transform(rE.aP2+aVAdd,aPoly2[3]);
454 pVirDev->DrawPolygon(aPoly2);
455 if (SetLineAttribute(rE)) {
456 sal_uInt16 i;
457 for (i=0; i<nN; i++) pVirDev->DrawLine(aPoly[i],aPoly2[i]);
458 }
459 }
460 }
461 }
462
463
DrawTextEntity(const DXFTextEntity & rE,const DXFTransform & rTransform)464 void DXF2GDIMetaFile::DrawTextEntity(const DXFTextEntity & rE, const DXFTransform & rTransform)
465 {
466 DXFVector aV;
467 Point aPt;
468 double fA;
469 sal_uInt16 nHeight;
470 short nAng;
471 ByteString aStr( rE.sText );
472 DXFTransform aT( DXFTransform(rE.fXScale,rE.fHeight,1.0,rE.fRotAngle,rE.aP0), rTransform );
473 aT.TransDir(DXFVector(0,1,0),aV);
474 nHeight=(sal_uInt16)(aV.Abs()+0.5);
475 fA=aT.CalcRotAngle();
476 nAng=(short)(fA*10.0+0.5);
477 aT.TransDir(DXFVector(1,0,0),aV);
478 if ( SetFontAttribute( rE,nAng, nHeight, aV. Abs() ) )
479 {
480 String aUString( aStr, pDXF->getTextEncoding() );
481 aT.Transform( DXFVector( 0, 0, 0 ), aPt );
482 pVirDev->DrawText( aPt, aUString );
483 }
484 }
485
486
487 // Draw a TEXT entity projected into the (3D) view, used when the drawing is
488 // rendered through a non-top viewport. VCL's DrawText can only place text with a
489 // position + uniform height + single rotation, so it cannot follow the shear /
490 // foreshortening a 3D projection produces. Instead we take the glyph OUTLINES and
491 // push them through the full transform like any other geometry, so the text lies
492 // in its projected plane. The flat 2D path (DrawTextEntity) is left untouched.
Draw3DTextEntity(const DXFTextEntity & rE,const DXFTransform & rTransform)493 void DXF2GDIMetaFile::Draw3DTextEntity(const DXFTextEntity & rE, const DXFTransform & rTransform)
494 {
495 ByteString aStr( rE.sText );
496 String aUString( aStr, pDXF->getTextEncoding() );
497 if ( aUString.Len()==0 ) return;
498
499 long nColor = GetEntityColor(rE);
500 if ( nColor<0 ) return;
501 Color aColor = ConvertColor((sal_uInt8)nColor);
502
503 // Extract the glyph outlines from a SCRATCH device, never from pVirDev: the
504 // recording device has output disabled, so its GetTextOutlines falls back to a
505 // bitmap path that fails ("could not create system bitmap"). A clean scalable
506 // font on a plain VirtualDevice takes the vector path. The nominal height is
507 // arbitrary — the extent is self-calibrated below.
508 const long nNominal = 1000;
509 Font aFont;
510 aFont.SetFamily(FAMILY_SWISS);
511 aFont.SetSize(Size(0,nNominal));
512 aFont.SetAlign(ALIGN_BASELINE);
513 VirtualDevice aTextDev;
514 aTextDev.SetFont(aFont);
515 PolyPolyVector aGlyphs;
516 sal_Bool bOK = aTextDev.GetTextOutlines( aGlyphs, aUString );
517 if ( !bOK || aGlyphs.empty() ) {
518 DrawTextEntity(rE,rTransform); // no outlines available -> flat fallback
519 return;
520 }
521
522 // GetTextOutlines returns the glyphs in an opaque internal scale (it toggles
523 // the map mode and rescales by a pixel factor), so we can't assume the height
524 // is nNominal. Self-calibrate: measure the real outline extent and normalise by
525 // its height, so one text-height maps to 1.0 regardless of the device scale.
526 double fMinY=0.0, fMaxY=0.0;
527 sal_Bool bFirst = sal_True;
528 sal_uInt32 g;
529 for ( g=0; g<aGlyphs.size(); g++ ) {
530 const PolyPolygon & rGlyph = aGlyphs[ g ];
531 sal_uInt16 c;
532 for ( c=0; c<rGlyph.Count(); c++ ) {
533 const Polygon & rContour = rGlyph[ c ];
534 sal_uInt16 i, nPts = rContour.GetSize();
535 for ( i=0; i<nPts; i++ ) {
536 const double y = (double)rContour[ i ].Y();
537 if ( bFirst ) { fMinY=fMaxY=y; bFirst=sal_False; }
538 else { if (y<fMinY) fMinY=y; if (y>fMaxY) fMaxY=y; }
539 }
540 }
541 }
542 const double fHeight = fMaxY - fMinY;
543 if ( fHeight <= 0.0 ) { // degenerate outlines -> flat fallback
544 DrawTextEntity(rE,rTransform);
545 return;
546 }
547 const double fInv = 1.0/fHeight;
548
549 // Text-local coords (baseline at Y=0, one text-height == 1.0, Y up) -> DXF
550 // text placement (width/height/rotation/insertion) -> the incoming extrusion+
551 // view transform. This is the same chain the renderer uses for geometry.
552 // The outlines are normalised to text-height units in BOTH axes, so X and Y
553 // must both scale by fHeight; fXScale (DXF group 41 width factor) is only an
554 // extra horizontal stretch on top (default 1.0). Scaling X by fXScale alone —
555 // as DrawTextEntity can, because it re-derives width from the font — would
556 // collapse the glyphs to a vertical sliver here.
557 const double fWScale = rE.fHeight * ( rE.fXScale>0.0 ? rE.fXScale : 1.0 );
558 DXFTransform aT( DXFTransform(fWScale,rE.fHeight,1.0,rE.fRotAngle,rE.aP0), rTransform );
559
560 if ( aActFillColor!=aColor ) pVirDev->SetFillColor( aActFillColor = aColor );
561 if ( aActLineColor!=aColor ) pVirDev->SetLineColor( aActLineColor = aColor );
562
563 for ( g=0; g<aGlyphs.size(); g++ ) {
564 const PolyPolygon & rGlyph = aGlyphs[ g ];
565 PolyPolygon aDevGlyph;
566 sal_uInt16 c;
567 for ( c=0; c<rGlyph.Count(); c++ ) {
568 const Polygon & rContour = rGlyph[ c ];
569 sal_uInt16 nPts = rContour.GetSize();
570 Polygon aDev( nPts );
571 sal_uInt16 i;
572 for ( i=0; i<nPts; i++ ) {
573 const Point & rP = rContour[ i ];
574 aT.Transform( DXFVector( (double)rP.X()*fInv,
575 -(double)rP.Y()*fInv, 0.0 ),
576 aDev[ i ] );
577 }
578 aDevGlyph.Insert( aDev );
579 }
580 pVirDev->DrawPolyPolygon( aDevGlyph );
581 }
582 }
583
584
DrawInsertEntity(const DXFInsertEntity & rE,const DXFTransform & rTransform)585 void DXF2GDIMetaFile::DrawInsertEntity(const DXFInsertEntity & rE, const DXFTransform & rTransform)
586 {
587 const DXFBlock * pB;
588 pB=pDXF->aBlocks.Search(rE.sName);
589 if (pB!=NULL) {
590 DXFTransform aDXFTransform1(1.0,1.0,1.0,DXFVector(0.0,0.0,0.0)-pB->aBasePoint);
591 DXFTransform aDXFTransform2(rE.fXScale,rE.fYScale,rE.fZScale,rE.fRotAngle,rE.aP0);
592 DXFTransform aT(
593 DXFTransform( aDXFTransform1, aDXFTransform2 ),
594 rTransform
595 );
596 long nSavedBlockColor, nSavedParentLayerColor;
597 DXFLineInfo aSavedBlockDXFLineInfo, aSavedParentLayerDXFLineInfo;
598 nSavedBlockColor=nBlockColor;
599 nSavedParentLayerColor=nParentLayerColor;
600 aSavedBlockDXFLineInfo=aBlockDXFLineInfo;
601 aSavedParentLayerDXFLineInfo=aParentLayerDXFLineInfo;
602 nBlockColor=GetEntityColor(rE);
603 aBlockDXFLineInfo=GetEntityDXFLineInfo(rE);
604 if (rE.sLayer[0]!='0' || rE.sLayer[1]!=0) {
605 DXFLayer * pLayer=pDXF->aTables.SearchLayer(rE.sLayer);
606 if (pLayer!=NULL) {
607 nParentLayerColor=pLayer->nColor;
608 aParentLayerDXFLineInfo=LTypeToDXFLineInfo(pLayer->sLineType);
609 }
610 }
611 DrawEntities(*pB,aT,sal_False);
612 aBlockDXFLineInfo=aSavedBlockDXFLineInfo;
613 aParentLayerDXFLineInfo=aSavedParentLayerDXFLineInfo;
614 nBlockColor=nSavedBlockColor;
615 nParentLayerColor=nSavedParentLayerColor;
616 }
617 }
618
619
DrawAttribEntity(const DXFAttribEntity & rE,const DXFTransform & rTransform)620 void DXF2GDIMetaFile::DrawAttribEntity(const DXFAttribEntity & rE, const DXFTransform & rTransform)
621 {
622 if ((rE.nAttrFlags&1)==0) {
623 DXFVector aV;
624 Point aPt;
625 double fA;
626 sal_uInt16 nHeight;
627 short nAng;
628 ByteString aStr( rE.sText );
629 DXFTransform aT( DXFTransform( rE.fXScale, rE.fHeight, 1.0, rE.fRotAngle, rE.aP0 ), rTransform );
630 aT.TransDir(DXFVector(0,1,0),aV);
631 nHeight=(sal_uInt16)(aV.Abs()+0.5);
632 fA=aT.CalcRotAngle();
633 nAng=(short)(fA*10.0+0.5);
634 aT.TransDir(DXFVector(1,0,0),aV);
635 if (SetFontAttribute(rE,nAng,nHeight,aV.Abs()))
636 {
637 String aUString( aStr, pDXF->getTextEncoding() );
638 aT.Transform( DXFVector( 0, 0, 0 ), aPt );
639 pVirDev->DrawText( aPt, aUString );
640 }
641 }
642 }
643
644
DrawPolyLineEntity(const DXFPolyLineEntity & rE,const DXFTransform & rTransform)645 void DXF2GDIMetaFile::DrawPolyLineEntity(const DXFPolyLineEntity & rE, const DXFTransform & rTransform)
646 {
647 sal_uInt16 i,nPolySize;
648 double fW;
649 const DXFBasicEntity * pBE;
650
651 nPolySize=0;
652 pBE=rE.pSucc;
653 while (pBE!=NULL && pBE->eType==DXF_VERTEX) {
654 nPolySize++;
655 pBE=pBE->pSucc;
656 }
657 if (nPolySize<2) return;
658 Polygon aPoly(nPolySize);
659 fW=0.0;
660 pBE=rE.pSucc;
661 for (i=0; i<nPolySize; i++) {
662 rTransform.Transform(((DXFVertexEntity*)pBE)->aP0,aPoly[i]);
663 if (i+1<nPolySize || (rE.nFlags&1)!=0) {
664 if (((DXFVertexEntity*)pBE)->fSWidth>=0.0) fW+=((DXFVertexEntity*)pBE)->fSWidth;
665 else fW+=rE.fSWidth;
666 if (((DXFVertexEntity*)pBE)->fEWidth>=0.0) fW+=((DXFVertexEntity*)pBE)->fEWidth;
667 else fW+=rE.fEWidth;
668 }
669 pBE=pBE->pSucc;
670 }
671 fW/=2.0;
672 if ((rE.nFlags&1)!=0) fW/=(double)nPolySize;
673 else fW/=(double)(nPolySize-1);
674 if (SetLineAttribute(rE,rTransform.TransLineWidth(fW))) {
675 if ((rE.nFlags&1)!=0) pVirDev->DrawPolygon(aPoly);
676 else pVirDev->DrawPolyLine(aPoly);
677 if (rE.fThickness!=0) {
678 Polygon aPoly2(nPolySize);
679 pBE=rE.pSucc;
680 for (i=0; i<nPolySize; i++) {
681 rTransform.Transform(
682 (((DXFVertexEntity*)pBE)->aP0)+DXFVector(0,0,rE.fThickness),
683 aPoly2[i]
684 );
685 pBE=pBE->pSucc;
686 }
687 if ((rE.nFlags&1)!=0) pVirDev->DrawPolygon(aPoly2);
688 else pVirDev->DrawPolyLine(aPoly2);
689 for (i=0; i<nPolySize; i++) pVirDev->DrawLine(aPoly[i],aPoly2[i]);
690 }
691 }
692 }
693
DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE,const DXFTransform & rTransform)694 void DXF2GDIMetaFile::DrawLWPolyLineEntity(const DXFLWPolyLineEntity & rE, const DXFTransform & rTransform )
695 {
696 const sal_Int32 nVtxCount = rE.nCount;
697 if ( nVtxCount <= 0 || rE.pP == NULL )
698 return;
699
700 double fW = rE.fConstantWidth;
701 if ( !SetLineAttribute( rE, rTransform.TransLineWidth( fW ) ) )
702 return;
703
704 const sal_Bool bClosed = ( rE.nFlags & 1 ) != 0;
705
706 // Build the outline in device space, expanding any segment that carries a
707 // non-zero bulge into an arc. In DXF a bulge is tan(sweep/4), so bulge 1.0
708 // is a 180 degree arc; a circle is commonly stored as two bulged segments
709 // (e.g. Eagle CAD). Straight segments (bulge 0) contribute just the vertex.
710 DXFPointArray aPtAry;
711 Point aPt;
712 for ( sal_Int32 i = 0; i < nVtxCount; i++ )
713 {
714 rTransform.Transform( rE.pP[ i ], aPt );
715 aPtAry.push_back( aPt );
716
717 sal_Int32 iNext = i + 1;
718 if ( iNext >= nVtxCount )
719 {
720 if ( !bClosed ) break; // open: no segment after the last vertex
721 iNext = 0; // closed: last vertex arcs back to the first
722 }
723
724 const double fBulge = ( rE.pBulge != NULL ) ? rE.pBulge[ i ] : 0.0;
725 if ( fBulge != 0.0 )
726 {
727 const DXFVector & rS = rE.pP[ i ];
728 const DXFVector & rEnd = rE.pP[ iNext ];
729 // Arc centre from the bulge (cotangent form): the centre lies on the
730 // chord's perpendicular bisector, offset by cot(sweep/2)/2 * chord.
731 const double fCot = 0.5 * ( 1.0 / fBulge - fBulge );
732 const double fCx = 0.5 * ( ( rS.fx + rEnd.fx ) + fCot * ( rS.fy - rEnd.fy ) );
733 const double fCy = 0.5 * ( ( rS.fy + rEnd.fy ) + fCot * ( rEnd.fx - rS.fx ) );
734 const double fRx = rS.fx - fCx;
735 const double fRy = rS.fy - fCy;
736 const double fRadius = sqrt( fRx * fRx + fRy * fRy );
737 const double fStartAng = atan2( fRy, fRx );
738 const double fSweep = 4.0 * atan( fBulge ); // signed: >0 = CCW
739 sal_Int32 nArcPoints = (sal_Int32)( fabs( fSweep ) / ( 2 * 3.14159265359 )
740 * (double)OptPointsPerCircle + 0.5 );
741 // Emit the interior arc samples; the start vertex is already pushed
742 // and the end vertex is pushed as the next loop's leading vertex.
743 for ( sal_Int32 k = 1; k < nArcPoints; k++ )
744 {
745 const double fAng = fStartAng + fSweep * (double)k / (double)nArcPoints;
746 rTransform.Transform(
747 DXFVector( fCx + fRadius * cos( fAng ),
748 fCy + fRadius * sin( fAng ),
749 rS.fz ),
750 aPt );
751 aPtAry.push_back( aPt );
752 }
753 }
754 }
755
756 const sal_Int32 nPolySize = (sal_Int32)aPtAry.size();
757 if ( nPolySize < 2 )
758 return;
759
760 if ( nPolySize <= 0xFFFF )
761 {
762 // Fits in a single tools Polygon (which is indexed by sal_uInt16).
763 Polygon aPoly( (sal_uInt16)nPolySize );
764 for ( sal_Int32 i = 0; i < nPolySize; i++ )
765 aPoly[ (sal_uInt16)i ] = aPtAry[ i ];
766 if ( bClosed )
767 pVirDev->DrawPolygon( aPoly );
768 else
769 pVirDev->DrawPolyLine( aPoly );
770 return;
771 }
772
773 // The tessellated outline can exceed the 0xFFFF points a tools Polygon holds.
774 // Render it as a sequence of Polygon segments that overlap by one point, so
775 // the whole line is drawn without truncation and the stroke stays continuous.
776 const sal_Int32 nMaxChunk = 0xFFFF;
777 sal_Int32 nStart = 0;
778 while ( nStart + 1 < nPolySize )
779 {
780 sal_Int32 nEnd = nStart + nMaxChunk;
781 if ( nEnd > nPolySize )
782 nEnd = nPolySize;
783 const sal_uInt16 nChunk = (sal_uInt16)( nEnd - nStart );
784 Polygon aChunk( nChunk );
785 for ( sal_uInt16 j = 0; j < nChunk; j++ )
786 aChunk[ j ] = aPtAry[ nStart + j ];
787 pVirDev->DrawPolyLine( aChunk );
788 nStart = nEnd - 1; // next segment shares this segment's last point
789 }
790 if ( bClosed )
791 {
792 // Close the outline: last point back to the first.
793 Polygon aClose( 2 );
794 aClose[ 0 ] = aPtAry[ nPolySize - 1 ];
795 aClose[ 1 ] = aPtAry[ 0 ];
796 pVirDev->DrawPolyLine( aClose );
797 }
798 }
799
DrawHatchEntity(const DXFHatchEntity & rE,const DXFTransform & rTransform)800 void DXF2GDIMetaFile::DrawHatchEntity(const DXFHatchEntity & rE, const DXFTransform & rTransform )
801 {
802 if ( !rE.nBoundaryPathCount )
803 return;
804
805 // Build the boundary as a PolyPolygon, tessellating curved edges so the
806 // area is measured correctly for both the solid fill and the pattern clip.
807 sal_Int32 j;
808 PolyPolygon aPolyPoly;
809 for ( j = 0; j < rE.nBoundaryPathCount; j++ )
810 {
811 DXFPointArray aPtAry;
812 const DXFBoundaryPathData& rPathData = rE.pBoundaryPathData[ j ];
813 if ( rPathData.bIsPolyLine )
814 {
815 sal_Int32 i;
816 for( i = 0; i < rPathData.nPointCount; i++ )
817 {
818 Point aPt;
819 rTransform.Transform( rPathData.pP[ i ], aPt );
820 aPtAry.push_back( aPt );
821 }
822 }
823 else
824 {
825 sal_uInt32 i;
826 for ( i = 0; i < rPathData.aEdges.size(); i++ )
827 {
828 const DXFEdgeType* pEdge = rPathData.aEdges[ i ];
829 switch( pEdge->nEdgeType )
830 {
831 case 1 :
832 {
833 Point aPt;
834 rTransform.Transform( ((DXFEdgeTypeLine*)pEdge)->aStartPoint, aPt );
835 aPtAry.push_back( aPt );
836 rTransform.Transform( ((DXFEdgeTypeLine*)pEdge)->aEndPoint, aPt );
837 aPtAry.push_back( aPt );
838 }
839 break;
840 case 2 :
841 {
842 // Circular arc edge: sample the sweep and push the points.
843 // Angles are in degrees; direction follows the CCW flag.
844 const DXFEdgeTypeCircularArc* pArc = (const DXFEdgeTypeCircularArc*)pEdge;
845 double fSweep = pArc->fEndAngle - pArc->fStartAngle;
846 if ( pArc->nIsCounterClockwiseFlag )
847 { while ( fSweep <= 0.0 ) fSweep += 360.0; }
848 else
849 { while ( fSweep >= 0.0 ) fSweep -= 360.0; }
850 sal_uInt16 nPts = (sal_uInt16)( fabs(fSweep)/360.0*(double)OptPointsPerCircle + 0.5 );
851 if ( nPts < 2 ) nPts = 2;
852 for ( sal_uInt16 k = 0; k < nPts; k++ )
853 {
854 double a = ( pArc->fStartAngle + fSweep*(double)k/(double)(nPts-1) )
855 * (3.14159265359/180.0);
856 Point aPt;
857 rTransform.Transform(
858 DXFVector( pArc->aCenter.fx + pArc->fRadius*cos(a),
859 pArc->aCenter.fy + pArc->fRadius*sin(a), 0.0 ), aPt );
860 aPtAry.push_back( aPt );
861 }
862 }
863 break;
864 case 3 : // elliptical arc: not tessellated (not seen in
865 case 4 : // practice here); spline edges store no control
866 break; // points, so both fall through as before.
867 }
868 }
869 }
870 sal_uInt16 i, nSize = (sal_uInt16)aPtAry.size();
871 if ( nSize )
872 {
873 Polygon aPoly( nSize );
874 for ( i = 0; i < nSize; i++ )
875 aPoly[ i ] = aPtAry[ i ];
876 aPolyPoly.Insert( aPoly, POLYPOLY_APPEND );
877 }
878 }
879 if ( !aPolyPoly.Count() )
880 return;
881
882 if ( rE.nFlags & 1 )
883 {
884 // Solid fill (group 70 bit 0): flood-fill the boundary in the entity colour.
885 SetAreaAttribute( rE );
886 pVirDev->DrawPolyPolygon( aPolyPoly );
887 }
888 else if ( rE.bHasPatternLine )
889 {
890 // Pattern fill: render the section lines with VCL's DrawHatch, which
891 // clips a line family to the boundary and records a MetaHatchAction.
892 // The DXF pattern is collapsed to a single/double/triple Hatch; the
893 // on-page angle and spacing come from mapping the pattern-definition
894 // line's direction and inter-line offset through rTransform, so any
895 // scale / rotation / block-insert nesting is accounted for.
896 long nColor = GetEntityColor( rE );
897 if ( nColor < 0 )
898 return;
899 Color aColor = ConvertColor( (sal_uInt8)nColor );
900
901 const double fPi = 3.14159265359;
902 double fA = rE.fPatternLineAngle * (fPi/180.0);
903 DXFVector aDir, aOff;
904 rTransform.TransDir( DXFVector( cos(fA), sin(fA), 0.0 ), aDir );
905 rTransform.TransDir( DXFVector( rE.fPatternLineOffsetX, rE.fPatternLineOffsetY, 0.0 ), aOff );
906
907 double fDirLen = sqrt( aDir.fx*aDir.fx + aDir.fy*aDir.fy );
908 if ( fDirLen < 1e-9 )
909 {
910 // degenerate direction: fall back to a bare outline (no blob).
911 SetLineAttribute( rE );
912 pVirDev->DrawPolyPolygon( aPolyPoly );
913 return;
914 }
915
916 // Perpendicular spacing between adjacent lines in device space, and the
917 // device line angle. VCL's angle is measured in the recorded coordinate
918 // system with its positive direction as (cos,-sin), hence -aDir.fy.
919 double fDist = fabs( aOff.fx*aDir.fy - aOff.fy*aDir.fx ) / fDirLen;
920 long nDistance = (long)( fDist + 0.5 );
921 if ( nDistance < 1 ) nDistance = 1;
922
923 double fAngle = atan2( -aDir.fy, aDir.fx ) * 1800.0 / fPi;
924 long nAngle10 = (long)( fAngle + (fAngle < 0.0 ? -0.5 : 0.5) );
925 nAngle10 %= 1800;
926 if ( nAngle10 < 0 )
927 nAngle10 += 1800;
928
929 HatchStyle eStyle = HATCH_SINGLE;
930 if ( rE.nHatchPatternDefinitionLines == 2 )
931 eStyle = HATCH_DOUBLE;
932 else if ( rE.nHatchPatternDefinitionLines >= 3 )
933 eStyle = HATCH_TRIPLE;
934
935 Hatch aHatch( eStyle, aColor, nDistance, (sal_uInt16)nAngle10 );
936 pVirDev->DrawHatch( aPolyPoly, aHatch );
937 }
938 else
939 {
940 // Pattern fill but no pattern-definition line was parsed: stroke the
941 // boundary outline only (transparent fill), never a solid blob.
942 SetLineAttribute( rE );
943 pVirDev->DrawPolyPolygon( aPolyPoly );
944 }
945 }
946
DrawEllipseEntity(const DXFEllipseEntity & rE,const DXFTransform & rTransform)947 void DXF2GDIMetaFile::DrawEllipseEntity(const DXFEllipseEntity & rE, const DXFTransform & rTransform)
948 {
949 if (SetLineAttribute(rE)==sal_False) return;
950
951 // Major axis vector (relative to centre) and the minor axis, which for the
952 // common planar case (extrusion 0,0,1) is ratio*(normal x major) =
953 // ratio*(-major.y, major.x, 0). A non-default extrusion is applied through
954 // rTransform by DrawEntities, so compute in the entity's own frame.
955 const DXFVector & aU = rE.aP1;
956 DXFVector aV(-aU.fy * rE.fRatio, aU.fx * rE.fRatio, 0.0);
957
958 double fSweep = rE.fEnd - rE.fStart;
959 while (fSweep <= 0.0) fSweep += 2*3.14159265359;
960 while (fSweep > 2*3.14159265359) fSweep -= 2*3.14159265359;
961
962 sal_uInt16 nPoints = (sal_uInt16)( fSweep/(2*3.14159265359)*(double)OptPointsPerCircle + 0.5 );
963 if (nPoints<2) nPoints=2;
964
965 Polygon aPoly(nPoints);
966 for (sal_uInt16 i=0; i<nPoints; i++) {
967 double t = rE.fStart + fSweep*(double)i/(double)(nPoints-1);
968 rTransform.Transform( rE.aP0 + aU*cos(t) + aV*sin(t), aPoly[i] );
969 }
970 pVirDev->DrawPolyLine(aPoly);
971 }
972
973
DrawSplineEntity(const DXFSplineEntity & rE,const DXFTransform & rTransform)974 void DXF2GDIMetaFile::DrawSplineEntity(const DXFSplineEntity & rE, const DXFTransform & rTransform)
975 {
976 // Non-uniform B-spline, evaluated with de Boor's algorithm and drawn as a
977 // polyline. Rational (weighted) splines are treated as non-rational (the
978 // weights are ignored) — sufficient for the planar curves this targets.
979 if ( rE.pControlPts==NULL || rE.pfKnots==NULL ) return;
980 const long p = rE.nDegree;
981 const long n = rE.nCtrlCount - 1;
982 if ( p < 1 || n < p ) return;
983 if ( rE.nKnotCount != rE.nCtrlCount + p + 1 ) return; // not a clamped B-spline
984 if ( SetLineAttribute(rE)==sal_False ) return;
985
986 const double * U = rE.pfKnots;
987 const double u0 = U[p];
988 const double u1 = U[n+1];
989 if ( u1 <= u0 ) return;
990
991 long nPoints = rE.nCtrlCount * 8;
992 if (nPoints < 2) nPoints = 2;
993 if (nPoints > 2000) nPoints = 2000;
994
995 Polygon aPoly((sal_uInt16)nPoints);
996 DXFVector * d = new DXFVector[p+1];
997 for (long i=0; i<nPoints; i++) {
998 double u = u0 + (u1-u0)*(double)i/(double)(nPoints-1);
999 if (u >= u1) u = u1 - (u1-u0)*1e-9; // stay inside the last knot span
1000
1001 // knot span k with U[k] <= u < U[k+1], clamped to [p, n]
1002 long k = p;
1003 while (k < n && u >= U[k+1]) k++;
1004
1005 long j, r;
1006 for (j=0; j<=p; j++) d[j] = rE.pControlPts[k-p+j];
1007 for (r=1; r<=p; r++) {
1008 for (j=p; j>=r; j--) {
1009 double fDenom = U[k+1+j-r] - U[k-p+j];
1010 double a = (fDenom!=0.0) ? (u - U[k-p+j])/fDenom : 0.0;
1011 d[j] = d[j-1]*(1.0-a) + d[j]*a;
1012 }
1013 }
1014 rTransform.Transform(d[p], aPoly[(sal_uInt16)i]);
1015 }
1016 delete[] d;
1017 pVirDev->DrawPolyLine(aPoly);
1018 }
1019
1020
Draw3DFaceEntity(const DXF3DFaceEntity & rE,const DXFTransform & rTransform)1021 void DXF2GDIMetaFile::Draw3DFaceEntity(const DXF3DFaceEntity & rE, const DXFTransform & rTransform)
1022 {
1023 sal_uInt16 nN,i;
1024 if (SetLineAttribute(rE)) {
1025 if (rE.aP2==rE.aP3) nN=3; else nN=4;
1026 Polygon aPoly(nN);
1027 rTransform.Transform(rE.aP0,aPoly[0]);
1028 rTransform.Transform(rE.aP1,aPoly[1]);
1029 rTransform.Transform(rE.aP2,aPoly[2]);
1030 if (nN>3) rTransform.Transform(rE.aP3,aPoly[3]);
1031 if ((rE.nIEFlags&0x0f)==0) pVirDev->DrawPolygon(aPoly);
1032 else {
1033 for (i=0; i<nN; i++) {
1034 if ( (rE.nIEFlags & (1<<i)) == 0 ) {
1035 pVirDev->DrawLine(aPoly[i],aPoly[(i+1)%nN]);
1036 }
1037 }
1038 }
1039 }
1040 }
1041
1042
DrawDimensionEntity(const DXFDimensionEntity & rE,const DXFTransform & rTransform)1043 void DXF2GDIMetaFile::DrawDimensionEntity(const DXFDimensionEntity & rE, const DXFTransform & rTransform)
1044 {
1045 const DXFBlock * pB;
1046 pB=pDXF->aBlocks.Search(rE.sPseudoBlock);
1047 if (pB!=NULL) {
1048 DXFTransform aT(
1049 DXFTransform(1.0,1.0,1.0,DXFVector(0.0,0.0,0.0)-pB->aBasePoint),
1050 rTransform
1051 );
1052 long nSavedBlockColor, nSavedParentLayerColor;
1053 DXFLineInfo aSavedBlockDXFLineInfo, aSavedParentLayerDXFLineInfo;
1054 nSavedBlockColor=nBlockColor;
1055 nSavedParentLayerColor=nParentLayerColor;
1056 aSavedBlockDXFLineInfo=aBlockDXFLineInfo;
1057 aSavedParentLayerDXFLineInfo=aParentLayerDXFLineInfo;
1058 nBlockColor=GetEntityColor(rE);
1059 aBlockDXFLineInfo=GetEntityDXFLineInfo(rE);
1060 if (rE.sLayer[0]!='0' || rE.sLayer[1]!=0) {
1061 DXFLayer * pLayer=pDXF->aTables.SearchLayer(rE.sLayer);
1062 if (pLayer!=NULL) {
1063 nParentLayerColor=pLayer->nColor;
1064 aParentLayerDXFLineInfo=LTypeToDXFLineInfo(pLayer->sLineType);
1065 }
1066 }
1067 DrawEntities(*pB,aT,sal_False);
1068 aBlockDXFLineInfo=aSavedBlockDXFLineInfo;
1069 aParentLayerDXFLineInfo=aSavedParentLayerDXFLineInfo;
1070 nBlockColor=nSavedBlockColor;
1071 nParentLayerColor=nSavedParentLayerColor;
1072 }
1073 }
1074
1075
DrawEntities(const DXFEntities & rEntities,const DXFTransform & rTransform,sal_Bool bTopEntities)1076 void DXF2GDIMetaFile::DrawEntities(const DXFEntities & rEntities,
1077 const DXFTransform & rTransform,
1078 sal_Bool bTopEntities)
1079 {
1080 sal_uLong nCount=0;
1081 DXFTransform aET;
1082 const DXFTransform * pT;
1083
1084 const DXFBasicEntity * pE=rEntities.pFirst;
1085
1086 while (pE!=NULL && bStatus==sal_True) {
1087 if (pE->nSpace==0) {
1088 if (pE->aExtrusion.fz==1.0 || DXFCoordsAreWCS(*pE)) {
1089 pT=&rTransform;
1090 }
1091 else {
1092 aET=DXFTransform(DXFTransform(pE->aExtrusion),rTransform);
1093 pT=&aET;
1094 }
1095 switch (pE->eType) {
1096 case DXF_LINE:
1097 DrawLineEntity((DXFLineEntity&)*pE,*pT);
1098 break;
1099 case DXF_POINT:
1100 DrawPointEntity((DXFPointEntity&)*pE,*pT);
1101 break;
1102 case DXF_CIRCLE:
1103 DrawCircleEntity((DXFCircleEntity&)*pE,*pT);
1104 break;
1105 case DXF_ARC:
1106 DrawArcEntity((DXFArcEntity&)*pE,*pT);
1107 break;
1108 case DXF_TRACE:
1109 DrawTraceEntity((DXFTraceEntity&)*pE,*pT);
1110 break;
1111 case DXF_SOLID:
1112 DrawSolidEntity((DXFSolidEntity&)*pE,*pT);
1113 break;
1114 case DXF_TEXT:
1115 if (b3DText)
1116 Draw3DTextEntity((DXFTextEntity&)*pE,*pT);
1117 else
1118 DrawTextEntity((DXFTextEntity&)*pE,*pT);
1119 break;
1120 case DXF_INSERT:
1121 DrawInsertEntity((DXFInsertEntity&)*pE,*pT);
1122 break;
1123 case DXF_ATTRIB:
1124 DrawAttribEntity((DXFAttribEntity&)*pE,*pT);
1125 break;
1126 case DXF_POLYLINE:
1127 DrawPolyLineEntity((DXFPolyLineEntity&)*pE,*pT);
1128 break;
1129 case DXF_LWPOLYLINE :
1130 DrawLWPolyLineEntity((DXFLWPolyLineEntity&)*pE, *pT);
1131 break;
1132 case DXF_HATCH :
1133 DrawHatchEntity((DXFHatchEntity&)*pE, *pT);
1134 break;
1135 case DXF_ELLIPSE:
1136 DrawEllipseEntity((DXFEllipseEntity&)*pE,*pT);
1137 break;
1138 case DXF_SPLINE:
1139 DrawSplineEntity((DXFSplineEntity&)*pE,*pT);
1140 break;
1141 case DXF_3DFACE:
1142 Draw3DFaceEntity((DXF3DFaceEntity&)*pE,*pT);
1143 break;
1144 case DXF_DIMENSION:
1145 DrawDimensionEntity((DXFDimensionEntity&)*pE,*pT);
1146 break;
1147 default:
1148 break; // four other values not handled -Wall
1149 }
1150 }
1151 pE=pE->pSucc;
1152 nCount++;
1153 if (bTopEntities) MayCallback(nCount);
1154 }
1155 }
1156
1157
DXF2GDIMetaFile()1158 DXF2GDIMetaFile::DXF2GDIMetaFile()
1159 {
1160 }
1161
1162
~DXF2GDIMetaFile()1163 DXF2GDIMetaFile::~DXF2GDIMetaFile()
1164 {
1165 }
1166
1167
Convert(const DXFRepresentation & rDXF,GDIMetaFile & rMTF,sal_uInt16 nminpercent,sal_uInt16 nmaxpercent)1168 sal_Bool DXF2GDIMetaFile::Convert(const DXFRepresentation & rDXF, GDIMetaFile & rMTF, sal_uInt16 nminpercent, sal_uInt16 nmaxpercent)
1169 {
1170 double fWidth,fHeight,fScale;
1171 DXFTransform aTransform;
1172 Size aPrefSize;
1173 const DXFLayer * pLayer;
1174 const DXFVPort * pVPort;
1175
1176 pVirDev = new VirtualDevice;
1177 pDXF = &rDXF;
1178 bStatus = sal_True;
1179
1180 OptPointsPerCircle=50;
1181
1182 nMinPercent=(sal_uLong)nminpercent;
1183 nMaxPercent=(sal_uLong)nmaxpercent;
1184 nLastPercent=nMinPercent;
1185 nMainEntitiesCount=CountEntities(pDXF->aEntities);
1186
1187 nBlockColor=7;
1188 aBlockDXFLineInfo.eStyle = LINE_SOLID;
1189 aBlockDXFLineInfo.fWidth = 0;
1190 aBlockDXFLineInfo.nDashCount = 0;
1191 aBlockDXFLineInfo.fDashLen = 0;
1192 aBlockDXFLineInfo.nDotCount = 0;
1193 aBlockDXFLineInfo.fDotLen = 0;
1194 aBlockDXFLineInfo.fDistance = 0;
1195
1196 pLayer=pDXF->aTables.SearchLayer("0");
1197 if (pLayer!=NULL) {
1198 nParentLayerColor=pLayer->nColor & 0xff;
1199 aParentLayerDXFLineInfo=LTypeToDXFLineInfo(pLayer->sLineType);
1200 }
1201 else {
1202 nParentLayerColor=7;
1203 aParentLayerDXFLineInfo.eStyle = LINE_SOLID;
1204 aParentLayerDXFLineInfo.fWidth = 0;
1205 aParentLayerDXFLineInfo.nDashCount = 0;
1206 aParentLayerDXFLineInfo.fDashLen = 0;
1207 aParentLayerDXFLineInfo.nDotCount = 0;
1208 aParentLayerDXFLineInfo.fDotLen = 0;
1209 aParentLayerDXFLineInfo.fDistance = 0;
1210 }
1211
1212 pVirDev->EnableOutput(sal_False);
1213 rMTF.Record(pVirDev);
1214
1215 aActLineColor = pVirDev->GetLineColor();
1216 aActFillColor = pVirDev->GetFillColor();
1217 aActFont = pVirDev->GetFont();
1218
1219 pVPort=pDXF->aTables.SearchVPort("*ACTIVE");
1220 if (pVPort!=NULL) {
1221 if (pVPort->aDirection.fx==0 && pVPort->aDirection.fy==0)
1222 pVPort=NULL;
1223 }
1224 // A non-top viewport means the drawing is projected in 3D; text then has to be
1225 // laid into that projection (Draw3DTextEntity) rather than drawn flat.
1226 b3DText = (pVPort!=NULL) ? sal_True : sal_False;
1227
1228 if (pVPort==NULL) {
1229 if (pDXF->aBoundingBox.bEmpty==sal_True)
1230 bStatus=sal_False;
1231 else {
1232 fWidth=pDXF->aBoundingBox.fMaxX-pDXF->aBoundingBox.fMinX;
1233 fHeight=pDXF->aBoundingBox.fMaxY-pDXF->aBoundingBox.fMinY;
1234 if (fWidth<=0 || fHeight<=0) {
1235 bStatus=sal_False;
1236 fScale = 0; // -Wall added this...
1237 }
1238 else {
1239 // Leave a small margin around the drawing. The larger extent is
1240 // scaled to fill the 10000-unit target exactly, so geometry that
1241 // lies right on the extent (e.g. a drawing frame's outer line)
1242 // would otherwise sit precisely on the fit boundary and be
1243 // clipped. This surfaced once issue 58347 made the bounding box
1244 // a tight fit to the geometry; the margin keeps every edge inside
1245 // the fitted area (symmetric, so all four sides get breathing room).
1246 const double fMargin =
1247 (fWidth>fHeight ? fWidth : fHeight) * 0.01;
1248 const double fFitWidth = fWidth + 2.0*fMargin;
1249 const double fFitHeight = fHeight + 2.0*fMargin;
1250 // if (fWidth<500.0 || fHeight<500.0 || fWidth>32767.0 || fHeight>32767.0) {
1251 if (fFitWidth>fFitHeight)
1252 fScale=10000.0/fFitWidth;
1253 else
1254 fScale=10000.0/fFitHeight;
1255 // }
1256 // else
1257 // fScale=1.0;
1258 aTransform=DXFTransform(fScale,-fScale,fScale,
1259 DXFVector((fMargin-pDXF->aBoundingBox.fMinX)*fScale,
1260 (pDXF->aBoundingBox.fMaxY+fMargin)*fScale,
1261 -pDXF->aBoundingBox.fMinZ*fScale));
1262 aPrefSize.Width() =(long)(fFitWidth*fScale+1.5);
1263 aPrefSize.Height()=(long)(fFitHeight*fScale+1.5);
1264 }
1265 }
1266 }
1267 else {
1268 fHeight=pVPort->fHeight;
1269 fWidth=fHeight*pVPort->fAspectRatio;
1270 // if (fWidth<500.0 || fHeight<500.0 || fWidth>32767.0 || fHeight>32767.0) {
1271 if (fWidth>fHeight)
1272 fScale=10000.0/fWidth;
1273 else
1274 fScale=10000.0/fHeight;
1275 // }
1276 // else
1277 // fScale=1.0;
1278 aTransform=DXFTransform(
1279 DXFTransform(pVPort->aDirection,pVPort->aTarget),
1280 DXFTransform(
1281 DXFTransform(1.0,-1.0,1.0,DXFVector(fWidth/2-pVPort->fCenterX,fHeight/2+pVPort->fCenterY,0)),
1282 DXFTransform(fScale,fScale,fScale,DXFVector(0,0,0))
1283 )
1284 );
1285 aPrefSize.Width() =(long)(fWidth*fScale+1.5);
1286 aPrefSize.Height()=(long)(fHeight*fScale+1.5);
1287 }
1288
1289 if (bStatus==sal_True)
1290 DrawEntities(pDXF->aEntities,aTransform,sal_True);
1291
1292 rMTF.Stop();
1293
1294 if ( bStatus==sal_True )
1295 {
1296 rMTF.SetPrefSize( aPrefSize );
1297
1298 // MapMode einfach, falls Grafik dann nicht zu klein wird (<0,5cm),
1299 // auf 1/100-mm (1/10-mm) setzen
1300 if( ( aPrefSize.Width() < 500 ) && ( aPrefSize.Height() < 500 ) )
1301 rMTF.SetPrefMapMode( MapMode( MAP_10TH_MM ) );
1302 else
1303 rMTF.SetPrefMapMode( MapMode( MAP_100TH_MM ) );
1304 }
1305
1306 delete pVirDev;
1307 return bStatus;
1308 }
1309