merge the formfield patch from ooo-build
[ooovba.git] / drawinglayer / source / primitive3d / sdrextrudeprimitive3d.cxx
blobb3e21fc793b22d3b3b96e756048260b7cbc63a7f
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: sdrextrudeprimitive3d.cxx,v $
7 * $Revision: 1.15 $
9 * last change: $Author: aw $ $Date: 2008-06-26 16:21:48 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32 * MA 02111-1307 USA
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/primitive3d/sdrextrudeprimitive3d.hxx>
40 #include <basegfx/matrix/b2dhommatrix.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <basegfx/polygon/b3dpolypolygontools.hxx>
43 #include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx>
44 #include <basegfx/tools/canvastools.hxx>
45 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
46 #include <drawinglayer/geometry/viewinformation3d.hxx>
47 #include <drawinglayer/primitive3d/hittestprimitive3d.hxx>
48 #include <drawinglayer/attribute/sdrattribute.hxx>
50 //////////////////////////////////////////////////////////////////////////////
52 using namespace com::sun::star;
54 //////////////////////////////////////////////////////////////////////////////
56 namespace drawinglayer
58 namespace primitive3d
60 Primitive3DSequence SdrExtrudePrimitive3D::createLocalDecomposition(const geometry::ViewInformation3D& rViewInformation) const
62 Primitive3DSequence aRetval;
64 // get slices
65 const Slice3DVector& rSliceVector = getSlices();
67 if(rSliceVector.size())
69 sal_uInt32 a;
71 // decide what to create
72 const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind());
73 const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind);
74 const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX());
75 const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY());
76 double fRelativeTextureWidth(1.0);
77 basegfx::B2DHomMatrix aTexTransform;
79 if(getSdrLFSAttribute().getFill() && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY))
81 const basegfx::B2DPolygon aFirstPolygon(maCorrectedPolyPolygon.getB2DPolygon(0L));
82 const double fFrontLength(basegfx::tools::getLength(aFirstPolygon));
83 const double fFrontArea(basegfx::tools::getArea(aFirstPolygon));
84 const double fSqrtFrontArea(sqrt(fFrontArea));
85 fRelativeTextureWidth = basegfx::fTools::equalZero(fSqrtFrontArea) ? 1.0 : fFrontLength / fSqrtFrontArea;
86 fRelativeTextureWidth = (double)((sal_uInt32)(fRelativeTextureWidth - 0.5));
88 if(fRelativeTextureWidth < 1.0)
90 fRelativeTextureWidth = 1.0;
93 aTexTransform.translate(-0.5, -0.5);
94 aTexTransform.scale(-1.0, -1.0);
95 aTexTransform.translate(0.5, 0.5);
96 aTexTransform.scale(fRelativeTextureWidth, 1.0);
99 // create geometry
100 ::std::vector< basegfx::B3DPolyPolygon > aFill;
101 extractPlanesFromSlice(aFill, rSliceVector,
102 bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), false,
103 0.5, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform);
105 // get full range
106 const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill));
108 // normal creation
109 if(getSdrLFSAttribute().getFill())
111 if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind)
113 applyNormalsKindSphereTo3DGeometry(aFill, aRange);
115 else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind)
117 applyNormalsKindFlatTo3DGeometry(aFill);
120 if(getSdr3DObjectAttribute().getNormalsInvert())
122 applyNormalsInvertTo3DGeometry(aFill);
126 // texture coordinates
127 if(getSdrLFSAttribute().getFill())
129 applyTextureTo3DGeometry(
130 getSdr3DObjectAttribute().getTextureProjectionX(),
131 getSdr3DObjectAttribute().getTextureProjectionY(),
132 aFill,
133 aRange,
134 getTextureSize());
137 if(getSdrLFSAttribute().getFill())
139 // add fill
140 aRetval = create3DPolyPolygonFillPrimitives(
141 aFill,
142 getTransform(),
143 getTextureSize(),
144 getSdr3DObjectAttribute(),
145 *getSdrLFSAttribute().getFill(),
146 getSdrLFSAttribute().getFillFloatTransGradient());
148 else
150 // create simplified 3d hit test geometry
151 const attribute::SdrFillAttribute aSimplifiedFillAttribute(0.0, basegfx::BColor(), 0, 0, 0);
153 aRetval = create3DPolyPolygonFillPrimitives(
154 aFill,
155 getTransform(),
156 getTextureSize(),
157 getSdr3DObjectAttribute(),
158 aSimplifiedFillAttribute,
161 // encapsulate in HitTestPrimitive3D and add
162 const Primitive3DReference xRef(new HitTestPrimitive3D(aRetval));
163 aRetval = Primitive3DSequence(&xRef, 1L);
166 // add line
167 if(getSdrLFSAttribute().getLine())
169 if(getSdr3DObjectAttribute().getReducedLineGeometry())
171 // create geometric outlines with reduced line geometry for chart.
172 const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector));
173 const sal_uInt32 nCount(aVerLine.count());
174 basegfx::B3DPolyPolygon aReducedLoops;
175 basegfx::B3DPolyPolygon aNewLineGeometry;
177 // sort out doubles (front and back planes when no edge rounding is done). Since
178 // this is a line geometry merged from PolyPolygons, loop over all Polygons
179 for(a = 0; a < nCount; a++)
181 const sal_uInt32 nReducedCount(aReducedLoops.count());
182 const basegfx::B3DPolygon aCandidate(aVerLine.getB3DPolygon(a));
183 bool bAdd(true);
185 if(nReducedCount)
187 for(sal_uInt32 b(0); bAdd && b < nReducedCount; b++)
189 if(aCandidate == aReducedLoops.getB3DPolygon(b))
191 bAdd = false;
196 if(bAdd)
198 aReducedLoops.append(aCandidate);
202 // from here work with reduced loops and reduced count without changing them
203 const sal_uInt32 nReducedCount(aReducedLoops.count());
205 if(nReducedCount > 1)
207 for(sal_uInt32 b(1); b < nReducedCount; b++)
209 // get loop pair
210 const basegfx::B3DPolygon aCandA(aReducedLoops.getB3DPolygon(b - 1));
211 const basegfx::B3DPolygon aCandB(aReducedLoops.getB3DPolygon(b));
213 // for each loop pair create the connection edges
214 createReducedOutlines(
215 rViewInformation,
216 getTransform(),
217 aCandA,
218 aCandB,
219 aNewLineGeometry);
223 // add reduced loops themselves
224 aNewLineGeometry.append(aReducedLoops);
226 // to create vertical edges at non-C1/C2 steady loops, use maCorrectedPolyPolygon
227 // directly since the 3D Polygons do not suport this.
229 // Unfortunately there is no bezier polygon provided by the chart module; one reason is
230 // that the API for extrude wants a 3D polygon geometry (for historical reasons, i guess)
231 // and those have no beziers. Another reason is that he chart module uses self-created
232 // stuff to create the 2D geometry (in ShapeFactory::createPieSegment), but this geometry
233 // does not contain bezier infos, either. The only way which is possible for now is to 'detect'
234 // candidates for vertical edges of pie segments by looking for the angles in the polygon.
236 // This is all not very well designed ATM. Ideally, the ReducedLineGeometry is responsible
237 // for creating the outer geometry edges (createReducedOutlines), but for special edges
238 // like the vertical ones for pie center and both start/end, the incarnation with the
239 // knowledge about that it needs to create those and IS a pie segment -> in this case,
240 // the chart itself.
241 const sal_uInt32 nPolyCount(maCorrectedPolyPolygon.count());
243 for(sal_uInt32 c(0); c < nPolyCount; c++)
245 const basegfx::B2DPolygon aCandidate(maCorrectedPolyPolygon.getB2DPolygon(c));
246 const sal_uInt32 nPointCount(aCandidate.count());
248 if(nPointCount > 2)
250 sal_uInt32 nIndexA(nPointCount);
251 sal_uInt32 nIndexB(nPointCount);
252 sal_uInt32 nIndexC(nPointCount);
254 for(sal_uInt32 d(0); d < nPointCount; d++)
256 const sal_uInt32 nPrevInd((d + nPointCount - 1) % nPointCount);
257 const sal_uInt32 nNextInd((d + 1) % nPointCount);
258 const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(d));
259 const basegfx::B2DVector aPrev(aCandidate.getB2DPoint(nPrevInd) - aPoint);
260 const basegfx::B2DVector aNext(aCandidate.getB2DPoint(nNextInd) - aPoint);
261 const double fAngle(aPrev.angle(aNext));
263 // take each angle which deviates more than 10% from going straight as
264 // special edge. This will detect the two outer edges of pie segments,
265 // but not always the center one (think about a near 180 degree pie)
266 if(F_PI - fabs(fAngle) > F_PI * 0.1)
268 if(nPointCount == nIndexA)
270 nIndexA = d;
272 else if(nPointCount == nIndexB)
274 nIndexB = d;
276 else if(nPointCount == nIndexC)
278 nIndexC = d;
279 d = nPointCount;
284 const bool bIndexAUsed(nIndexA != nPointCount);
285 const bool bIndexBUsed(nIndexB != nPointCount);
286 bool bIndexCUsed(nIndexC != nPointCount);
288 if(bIndexCUsed)
290 // already three special edges found, so the center one was already detected
291 // and does not need to be searched
293 else if(bIndexAUsed && bIndexBUsed)
295 // outer edges detected (they are approx. 90 degrees), but center one not.
296 // Look with the knowledge that it's in-between the two found ones
297 if(((nIndexA + 2) % nPointCount) == nIndexB)
299 nIndexC = (nIndexA + 1) % nPointCount;
301 else if(((nIndexA + nPointCount - 2) % nPointCount) == nIndexB)
303 nIndexC = (nIndexA + nPointCount - 1) % nPointCount;
306 bIndexCUsed = (nIndexC != nPointCount);
309 if(bIndexAUsed)
311 const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexA));
312 const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0);
313 const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth());
314 basegfx::B3DPolygon aToBeAdded;
316 aToBeAdded.append(aStart);
317 aToBeAdded.append(aEnd);
318 aNewLineGeometry.append(aToBeAdded);
321 if(bIndexBUsed)
323 const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexB));
324 const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0);
325 const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth());
326 basegfx::B3DPolygon aToBeAdded;
328 aToBeAdded.append(aStart);
329 aToBeAdded.append(aEnd);
330 aNewLineGeometry.append(aToBeAdded);
333 if(bIndexCUsed)
335 const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexC));
336 const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0);
337 const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth());
338 basegfx::B3DPolygon aToBeAdded;
340 aToBeAdded.append(aStart);
341 aToBeAdded.append(aEnd);
342 aNewLineGeometry.append(aToBeAdded);
347 // append loops themselves
348 aNewLineGeometry.append(aReducedLoops);
350 if(aNewLineGeometry.count())
352 const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(aNewLineGeometry, getTransform(), *getSdrLFSAttribute().getLine()));
353 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines);
356 else
358 // extract line geometry from slices
359 const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, false));
360 const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector));
362 // add horizontal lines
363 const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives(aHorLine, getTransform(), *getSdrLFSAttribute().getLine()));
364 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines);
366 // add vertical lines
367 const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives(aVerLine, getTransform(), *getSdrLFSAttribute().getLine()));
368 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines);
372 // add shadow
373 if(getSdrLFSAttribute().getShadow() && aRetval.hasElements())
375 const Primitive3DSequence aShadow(createShadowPrimitive3D(aRetval, *getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
376 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow);
380 return aRetval;
383 void SdrExtrudePrimitive3D::impCreateSlices()
385 // prepare the polygon. No double points, correct orientations and a correct
386 // outmost polygon are needed
387 maCorrectedPolyPolygon = getPolyPolygon();
388 maCorrectedPolyPolygon.removeDoublePoints();
389 maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon);
390 maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon);
392 // prepare slices as geometry
393 createExtrudeSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getDepth(), getCharacterMode(), getCloseFront(), getCloseBack());
396 const Slice3DVector& SdrExtrudePrimitive3D::getSlices() const
398 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine()
399 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart
400 if(getPolyPolygon().count() && !maSlices.size())
402 ::osl::Mutex m_mutex;
403 const_cast< SdrExtrudePrimitive3D& >(*this).impCreateSlices();
406 return maSlices;
409 SdrExtrudePrimitive3D::SdrExtrudePrimitive3D(
410 const basegfx::B3DHomMatrix& rTransform,
411 const basegfx::B2DVector& rTextureSize,
412 const attribute::SdrLineFillShadowAttribute& rSdrLFSAttribute,
413 const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute,
414 const basegfx::B2DPolyPolygon& rPolyPolygon,
415 double fDepth,
416 double fDiagonal,
417 double fBackScale,
418 bool bSmoothNormals,
419 bool bSmoothHorizontalNormals,
420 bool bSmoothLids,
421 bool bCharacterMode,
422 bool bCloseFront,
423 bool bCloseBack)
424 : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute),
425 maCorrectedPolyPolygon(),
426 maSlices(),
427 maPolyPolygon(rPolyPolygon),
428 mfDepth(fDepth),
429 mfDiagonal(fDiagonal),
430 mfBackScale(fBackScale),
431 mpLastRLGViewInformation(0),
432 mbSmoothNormals(bSmoothNormals),
433 mbSmoothHorizontalNormals(bSmoothHorizontalNormals),
434 mbSmoothLids(bSmoothLids),
435 mbCharacterMode(bCharacterMode),
436 mbCloseFront(bCloseFront),
437 mbCloseBack(bCloseBack)
439 // make sure depth is positive
440 if(basegfx::fTools::lessOrEqual(getDepth(), 0.0))
442 mfDepth = 0.0;
445 // make sure the percentage value getDiagonal() is between 0.0 and 1.0
446 if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0))
448 mfDiagonal = 0.0;
450 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0))
452 mfDiagonal = 1.0;
455 // no close front/back when polygon is not closed
456 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed())
458 mbCloseFront = mbCloseBack = false;
461 // no edge rounding when not closing
462 if(!getCloseFront() && !getCloseBack())
464 mfDiagonal = 0.0;
468 SdrExtrudePrimitive3D::~SdrExtrudePrimitive3D()
470 if(mpLastRLGViewInformation)
472 delete mpLastRLGViewInformation;
476 bool SdrExtrudePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
478 if(SdrPrimitive3D::operator==(rPrimitive))
480 const SdrExtrudePrimitive3D& rCompare = static_cast< const SdrExtrudePrimitive3D& >(rPrimitive);
482 return (getPolyPolygon() == rCompare.getPolyPolygon()
483 && getDepth() == rCompare.getDepth()
484 && getDiagonal() == rCompare.getDiagonal()
485 && getBackScale() == rCompare.getBackScale()
486 && getSmoothNormals() == rCompare.getSmoothNormals()
487 && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals()
488 && getSmoothLids() == rCompare.getSmoothLids()
489 && getCharacterMode() == rCompare.getCharacterMode()
490 && getCloseFront() == rCompare.getCloseFront()
491 && getCloseBack() == rCompare.getCloseBack());
494 return false;
497 basegfx::B3DRange SdrExtrudePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const
499 // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2
500 // The parent implementation which uses the ranges of the decomposition would be more
501 // corrcet, but for historical reasons it is necessary to do the old method: To get
502 // the range of the non-transformed geometry and transform it then. This leads to different
503 // ranges where the new method is more correct, but the need to keep the old behaviour
504 // has priority here.
505 return get3DRangeFromSlices(getSlices());
508 Primitive3DSequence SdrExtrudePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const
510 if(getSdr3DObjectAttribute().getReducedLineGeometry())
512 if(!mpLastRLGViewInformation ||
513 (getLocalDecomposition().hasElements()
514 && *mpLastRLGViewInformation != rViewInformation))
516 // conditions of last local decomposition with reduced lines have changed. Remember
517 // new one and clear current decompositiopn
518 ::osl::Mutex m_mutex;
519 SdrExtrudePrimitive3D* pThat = const_cast< SdrExtrudePrimitive3D* >(this);
520 pThat->setLocalDecomposition(Primitive3DSequence());
521 delete pThat->mpLastRLGViewInformation;
522 pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation);
526 // no test for buffering needed, call parent
527 return SdrPrimitive3D::get3DDecomposition(rViewInformation);
530 // provide unique ID
531 ImplPrimitrive3DIDBlock(SdrExtrudePrimitive3D, PRIMITIVE3D_ID_SDREXTRUDEPRIMITIVE3D)
533 } // end of namespace primitive3d
534 } // end of namespace drawinglayer
536 //////////////////////////////////////////////////////////////////////////////
537 // eof