xref: /trunk/main/drawinglayer/source/primitive3d/hatchtextureprimitive3d.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_drawinglayer.hxx"
30 
31 #include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx>
32 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
33 #include <basegfx/polygon/b2dpolypolygon.hxx>
34 #include <basegfx/polygon/b3dpolygon.hxx>
35 #include <basegfx/polygon/b2dpolygon.hxx>
36 #include <basegfx/polygon/b2dpolypolygontools.hxx>
37 #include <basegfx/range/b2drange.hxx>
38 #include <drawinglayer/texture/texture.hxx>
39 #include <basegfx/polygon/b2dpolygonclipper.hxx>
40 #include <basegfx/matrix/b3dhommatrix.hxx>
41 #include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
42 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
43 
44 //////////////////////////////////////////////////////////////////////////////
45 
46 using namespace com::sun::star;
47 
48 //////////////////////////////////////////////////////////////////////////////
49 
50 namespace drawinglayer
51 {
52     namespace primitive3d
53     {
54         Primitive3DSequence HatchTexturePrimitive3D::impCreate3DDecomposition() const
55         {
56             Primitive3DSequence aRetval;
57 
58             if(getChildren().hasElements())
59             {
60                 const Primitive3DSequence aSource(getChildren());
61                 const sal_uInt32 nSourceCount(aSource.getLength());
62                 std::vector< Primitive3DReference > aDestination;
63 
64                 for(sal_uInt32 a(0); a < nSourceCount; a++)
65                 {
66                     // get reference
67                     const Primitive3DReference xReference(aSource[a]);
68 
69                     if(xReference.is())
70                     {
71                         // try to cast to BasePrimitive2D implementation
72                         const BasePrimitive3D* pBasePrimitive = dynamic_cast< const BasePrimitive3D* >(xReference.get());
73 
74                         if(pBasePrimitive)
75                         {
76                             // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
77                             // not all content is needed, remove transparencies and ModifiedColorPrimitives
78                             switch(pBasePrimitive->getPrimitive3DID())
79                             {
80                                 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
81                                 {
82                                     // polyPolygonMaterialPrimitive3D, check texturing and hatching
83                                     const PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const PolyPolygonMaterialPrimitive3D& >(*pBasePrimitive);
84                                     const basegfx::B3DPolyPolygon aFillPolyPolygon(rPrimitive.getB3DPolyPolygon());
85 
86                                     if(maHatch.isFillBackground())
87                                     {
88                                         // add original primitive for background
89                                         aDestination.push_back(xReference);
90                                     }
91 
92                                     if(aFillPolyPolygon.areTextureCoordinatesUsed())
93                                     {
94                                         const sal_uInt32 nPolyCount(aFillPolyPolygon.count());
95                                         basegfx::B2DPolyPolygon aTexPolyPolygon;
96                                         basegfx::B2DPoint a2N;
97                                         basegfx::B2DVector a2X, a2Y;
98                                         basegfx::B3DPoint a3N;
99                                         basegfx::B3DVector a3X, a3Y;
100                                         bool b2N(false), b2X(false), b2Y(false);
101 
102                                         for(sal_uInt32 b(0); b < nPolyCount; b++)
103                                         {
104                                             const basegfx::B3DPolygon aPartPoly(aFillPolyPolygon.getB3DPolygon(b));
105                                             const sal_uInt32 nPointCount(aPartPoly.count());
106                                             basegfx::B2DPolygon aTexPolygon;
107 
108                                             for(sal_uInt32 c(0); c < nPointCount; c++)
109                                             {
110                                                 const basegfx::B2DPoint a2Candidate(aPartPoly.getTextureCoordinate(c));
111 
112                                                 if(!b2N)
113                                                 {
114                                                     a2N = a2Candidate;
115                                                     a3N = aPartPoly.getB3DPoint(c);
116                                                     b2N = true;
117                                                 }
118                                                 else if(!b2X && !a2N.equal(a2Candidate))
119                                                 {
120                                                     a2X = a2Candidate - a2N;
121                                                     a3X = aPartPoly.getB3DPoint(c) - a3N;
122                                                     b2X = true;
123                                                 }
124                                                 else if(!b2Y && !a2N.equal(a2Candidate) && !a2X.equal(a2Candidate))
125                                                 {
126                                                     a2Y = a2Candidate - a2N;
127 
128                                                     const double fCross(a2X.cross(a2Y));
129 
130                                                     if(!basegfx::fTools::equalZero(fCross))
131                                                     {
132                                                         a3Y = aPartPoly.getB3DPoint(c) - a3N;
133                                                         b2Y = true;
134                                                     }
135                                                 }
136 
137                                                 aTexPolygon.append(a2Candidate);
138                                             }
139 
140                                             aTexPolygon.setClosed(true);
141                                             aTexPolyPolygon.append(aTexPolygon);
142                                         }
143 
144                                         if(b2N && b2X && b2Y)
145                                         {
146                                             // found two linearly independent 2D vectors
147                                             // get 2d range of texture coordinates
148                                             const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aTexPolyPolygon));
149                                             const basegfx::BColor aHatchColor(getHatch().getColor());
150                                             const double fAngle(getHatch().getAngle());
151                                             ::std::vector< basegfx::B2DHomMatrix > aMatrices;
152 
153                                             // get hatch transformations
154                                             switch(getHatch().getStyle())
155                                             {
156                                                 case attribute::HATCHSTYLE_TRIPLE:
157                                                 {
158                                                     // rotated 45 degrees
159                                                     texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle - F_PI4);
160                                                     aHatch.appendTransformations(aMatrices);
161                                                 }
162                                                 case attribute::HATCHSTYLE_DOUBLE:
163                                                 {
164                                                     // rotated 90 degrees
165                                                     texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle - F_PI2);
166                                                     aHatch.appendTransformations(aMatrices);
167                                                 }
168                                                 case attribute::HATCHSTYLE_SINGLE:
169                                                 {
170                                                     // angle as given
171                                                     texture::GeoTexSvxHatch aHatch(aOutlineRange, getHatch().getDistance(), fAngle);
172                                                     aHatch.appendTransformations(aMatrices);
173                                                 }
174                                             }
175 
176                                             // create geometry from unit line
177                                             basegfx::B2DPolyPolygon a2DHatchLines;
178                                             basegfx::B2DPolygon a2DUnitLine;
179                                             a2DUnitLine.append(basegfx::B2DPoint(0.0, 0.0));
180                                             a2DUnitLine.append(basegfx::B2DPoint(1.0, 0.0));
181 
182                                             for(sal_uInt32 c(0); c < aMatrices.size(); c++)
183                                             {
184                                                 const basegfx::B2DHomMatrix& rMatrix = aMatrices[c];
185                                                 basegfx::B2DPolygon aNewLine(a2DUnitLine);
186                                                 aNewLine.transform(rMatrix);
187                                                 a2DHatchLines.append(aNewLine);
188                                             }
189 
190                                             if(a2DHatchLines.count())
191                                             {
192                                                 // clip against texture polygon
193                                                 a2DHatchLines = basegfx::tools::clipPolyPolygonOnPolyPolygon(a2DHatchLines, aTexPolyPolygon, true, true);
194                                             }
195 
196                                             if(a2DHatchLines.count())
197                                             {
198                                                 // create 2d matrix with 2d vectors as column vectors and 2d point as offset, this represents
199                                                 // a coordinate system transformation from unit coordinates to the new coordinate system
200                                                 basegfx::B2DHomMatrix a2D;
201                                                 a2D.set(0, 0, a2X.getX());
202                                                 a2D.set(1, 0, a2X.getY());
203                                                 a2D.set(0, 1, a2Y.getX());
204                                                 a2D.set(1, 1, a2Y.getY());
205                                                 a2D.set(0, 2, a2N.getX());
206                                                 a2D.set(1, 2, a2N.getY());
207 
208                                                 // invert that transformation, so we have a back-transformation from texture coordinates
209                                                 // to unit coordinates
210                                                 a2D.invert();
211                                                 a2DHatchLines.transform(a2D);
212 
213                                                 // expand back-transformated geometry tpo 3D
214                                                 basegfx::B3DPolyPolygon a3DHatchLines(basegfx::tools::createB3DPolyPolygonFromB2DPolyPolygon(a2DHatchLines, 0.0));
215 
216                                                 // create 3d matrix with 3d vectors as column vectors (0,0,1 as Z) and 3d point as offset, this represents
217                                                 // a coordinate system transformation from unit coordinates to the object's 3d coordinate system
218                                                 basegfx::B3DHomMatrix a3D;
219                                                 a3D.set(0, 0, a3X.getX());
220                                                 a3D.set(1, 0, a3X.getY());
221                                                 a3D.set(2, 0, a3X.getZ());
222                                                 a3D.set(0, 1, a3Y.getX());
223                                                 a3D.set(1, 1, a3Y.getY());
224                                                 a3D.set(2, 1, a3Y.getZ());
225                                                 a3D.set(0, 3, a3N.getX());
226                                                 a3D.set(1, 3, a3N.getY());
227                                                 a3D.set(2, 3, a3N.getZ());
228 
229                                                 // transform hatch lines to 3D object coordinates
230                                                 a3DHatchLines.transform(a3D);
231 
232                                                 // build primitives from this geometry
233                                                 const sal_uInt32 nHatchLines(a3DHatchLines.count());
234 
235                                                 for(sal_uInt32 d(0); d < nHatchLines; d++)
236                                                 {
237                                                     const Primitive3DReference xRef(new PolygonHairlinePrimitive3D(a3DHatchLines.getB3DPolygon(d), aHatchColor));
238                                                     aDestination.push_back(xRef);
239                                                 }
240                                             }
241                                         }
242                                     }
243 
244                                     break;
245                                 }
246                                 default :
247                                 {
248                                     // add reference to result
249                                     aDestination.push_back(xReference);
250                                     break;
251                                 }
252                             }
253                         }
254                         else
255                         {
256                             // unknown implementation, add to result
257                             aDestination.push_back(xReference);
258                         }
259                     }
260                 }
261 
262                 // prepare return value
263                 const sal_uInt32 nDestSize(aDestination.size());
264                 aRetval.realloc(nDestSize);
265 
266                 for(sal_uInt32 b(0); b < nDestSize; b++)
267                 {
268                     aRetval[b] = aDestination[b];
269                 }
270             }
271 
272             return aRetval;
273         }
274 
275         HatchTexturePrimitive3D::HatchTexturePrimitive3D(
276             const attribute::FillHatchAttribute& rHatch,
277             const Primitive3DSequence& rChildren,
278             const basegfx::B2DVector& rTextureSize,
279             bool bModulate,
280             bool bFilter)
281         :   TexturePrimitive3D(rChildren, rTextureSize, bModulate, bFilter),
282             maHatch(rHatch),
283             maBuffered3DDecomposition()
284         {
285         }
286 
287         bool HatchTexturePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
288         {
289             if(TexturePrimitive3D::operator==(rPrimitive))
290             {
291                 const HatchTexturePrimitive3D& rCompare = (HatchTexturePrimitive3D&)rPrimitive;
292 
293                 return (getHatch() == rCompare.getHatch());
294             }
295 
296             return false;
297         }
298 
299         Primitive3DSequence HatchTexturePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const
300         {
301             ::osl::MutexGuard aGuard( m_aMutex );
302 
303             if(!getBuffered3DDecomposition().hasElements())
304             {
305                 const Primitive3DSequence aNewSequence(impCreate3DDecomposition());
306                 const_cast< HatchTexturePrimitive3D* >(this)->setBuffered3DDecomposition(aNewSequence);
307             }
308 
309             return getBuffered3DDecomposition();
310         }
311 
312         // provide unique ID
313         ImplPrimitrive3DIDBlock(HatchTexturePrimitive3D, PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D)
314 
315     } // end of namespace primitive3d
316 } // end of namespace drawinglayer
317 
318 //////////////////////////////////////////////////////////////////////////////
319 // eof
320