1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx>
21 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
22 #include <basegfx/polygon/b2dpolypolygon.hxx>
23 #include <basegfx/polygon/b3dpolygon.hxx>
24 #include <basegfx/polygon/b2dpolygon.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <basegfx/range/b2drange.hxx>
27 #include <drawinglayer/texture/texture.hxx>
28 #include <basegfx/polygon/b2dpolygonclipper.hxx>
29 #include <basegfx/matrix/b3dhommatrix.hxx>
30 #include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
31 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
34 using namespace com::sun::star
;
37 namespace drawinglayer
41 Primitive3DContainer
HatchTexturePrimitive3D::impCreate3DDecomposition() const
43 Primitive3DContainer aRetval
;
45 if(!getChildren().empty())
47 const Primitive3DContainer
aSource(getChildren());
48 const size_t nSourceCount(aSource
.size());
49 std::vector
< Primitive3DReference
> aDestination
;
51 for(size_t a(0); a
< nSourceCount
; a
++)
54 const Primitive3DReference
xReference(aSource
[a
]);
58 // try to cast to BasePrimitive2D implementation
59 const BasePrimitive3D
* pBasePrimitive
= dynamic_cast< const BasePrimitive3D
* >(xReference
.get());
63 // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
64 // not all content is needed, remove transparencies and ModifiedColorPrimitives
65 switch(pBasePrimitive
->getPrimitive3DID())
67 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D
:
69 // polyPolygonMaterialPrimitive3D, check texturing and hatching
70 const PolyPolygonMaterialPrimitive3D
& rPrimitive
= static_cast< const PolyPolygonMaterialPrimitive3D
& >(*pBasePrimitive
);
71 const basegfx::B3DPolyPolygon
& aFillPolyPolygon(rPrimitive
.getB3DPolyPolygon());
73 if(maHatch
.isFillBackground())
75 // add original primitive for background
76 aDestination
.push_back(xReference
);
79 if(aFillPolyPolygon
.areTextureCoordinatesUsed())
81 const sal_uInt32
nPolyCount(aFillPolyPolygon
.count());
82 basegfx::B2DPolyPolygon aTexPolyPolygon
;
83 basegfx::B2DPoint a2N
;
84 basegfx::B2DVector a2X
, a2Y
;
85 basegfx::B3DPoint a3N
;
86 basegfx::B3DVector a3X
, a3Y
;
87 bool b2N(false), b2X(false), b2Y(false);
89 for(sal_uInt32
b(0); b
< nPolyCount
; b
++)
91 const basegfx::B3DPolygon
& aPartPoly(aFillPolyPolygon
.getB3DPolygon(b
));
92 const sal_uInt32
nPointCount(aPartPoly
.count());
93 basegfx::B2DPolygon aTexPolygon
;
95 for(sal_uInt32
c(0); c
< nPointCount
; c
++)
97 const basegfx::B2DPoint
a2Candidate(aPartPoly
.getTextureCoordinate(c
));
102 a3N
= aPartPoly
.getB3DPoint(c
);
105 else if(!b2X
&& !a2N
.equal(a2Candidate
))
107 a2X
= a2Candidate
- a2N
;
108 a3X
= aPartPoly
.getB3DPoint(c
) - a3N
;
111 else if(!b2Y
&& !a2N
.equal(a2Candidate
) && !a2X
.equal(a2Candidate
))
113 a2Y
= a2Candidate
- a2N
;
115 const double fCross(a2X
.cross(a2Y
));
117 if(!basegfx::fTools::equalZero(fCross
))
119 a3Y
= aPartPoly
.getB3DPoint(c
) - a3N
;
124 aTexPolygon
.append(a2Candidate
);
127 aTexPolygon
.setClosed(true);
128 aTexPolyPolygon
.append(aTexPolygon
);
131 if(b2N
&& b2X
&& b2Y
)
133 // found two linearly independent 2D vectors
134 // get 2d range of texture coordinates
135 const basegfx::B2DRange
aOutlineRange(basegfx::utils::getRange(aTexPolyPolygon
));
136 const basegfx::BColor
aHatchColor(getHatch().getColor());
137 const double fAngle(getHatch().getAngle());
138 std::vector
< basegfx::B2DHomMatrix
> aMatrices
;
140 // get hatch transformations
141 switch(getHatch().getStyle())
143 case attribute::HatchStyle::Triple
:
145 // rotated 45 degrees
146 texture::GeoTexSvxHatch
aHatch(
149 getHatch().getDistance(),
152 aHatch
.appendTransformations(aMatrices
);
156 case attribute::HatchStyle::Double
:
158 // rotated 90 degrees
159 texture::GeoTexSvxHatch
aHatch(
162 getHatch().getDistance(),
165 aHatch
.appendTransformations(aMatrices
);
169 case attribute::HatchStyle::Single
:
172 texture::GeoTexSvxHatch
aHatch(
175 getHatch().getDistance(),
178 aHatch
.appendTransformations(aMatrices
);
182 // create geometry from unit line
183 basegfx::B2DPolyPolygon a2DHatchLines
;
184 basegfx::B2DPolygon a2DUnitLine
;
185 a2DUnitLine
.append(basegfx::B2DPoint(0.0, 0.0));
186 a2DUnitLine
.append(basegfx::B2DPoint(1.0, 0.0));
188 for(const basegfx::B2DHomMatrix
& rMatrix
: aMatrices
)
190 basegfx::B2DPolygon
aNewLine(a2DUnitLine
);
191 aNewLine
.transform(rMatrix
);
192 a2DHatchLines
.append(aNewLine
);
195 if(a2DHatchLines
.count())
197 // clip against texture polygon
198 a2DHatchLines
= basegfx::utils::clipPolyPolygonOnPolyPolygon(a2DHatchLines
, aTexPolyPolygon
, true, true);
201 if(a2DHatchLines
.count())
203 // create 2d matrix with 2d vectors as column vectors and 2d point as offset, this represents
204 // a coordinate system transformation from unit coordinates to the new coordinate system
205 basegfx::B2DHomMatrix a2D
;
206 a2D
.set(0, 0, a2X
.getX());
207 a2D
.set(1, 0, a2X
.getY());
208 a2D
.set(0, 1, a2Y
.getX());
209 a2D
.set(1, 1, a2Y
.getY());
210 a2D
.set(0, 2, a2N
.getX());
211 a2D
.set(1, 2, a2N
.getY());
213 // invert that transformation, so we have a back-transformation from texture coordinates
214 // to unit coordinates
216 a2DHatchLines
.transform(a2D
);
218 // expand back-transformed geometry to 3D
219 basegfx::B3DPolyPolygon
a3DHatchLines(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(a2DHatchLines
, 0.0));
221 // create 3d matrix with 3d vectors as column vectors (0,0,1 as Z) and 3d point as offset, this represents
222 // a coordinate system transformation from unit coordinates to the object's 3d coordinate system
223 basegfx::B3DHomMatrix a3D
;
224 a3D
.set(0, 0, a3X
.getX());
225 a3D
.set(1, 0, a3X
.getY());
226 a3D
.set(2, 0, a3X
.getZ());
227 a3D
.set(0, 1, a3Y
.getX());
228 a3D
.set(1, 1, a3Y
.getY());
229 a3D
.set(2, 1, a3Y
.getZ());
230 a3D
.set(0, 3, a3N
.getX());
231 a3D
.set(1, 3, a3N
.getY());
232 a3D
.set(2, 3, a3N
.getZ());
234 // transform hatch lines to 3D object coordinates
235 a3DHatchLines
.transform(a3D
);
237 // build primitives from this geometry
238 const sal_uInt32
nHatchLines(a3DHatchLines
.count());
240 for(sal_uInt32
d(0); d
< nHatchLines
; d
++)
242 const Primitive3DReference
xRef(new PolygonHairlinePrimitive3D(a3DHatchLines
.getB3DPolygon(d
), aHatchColor
));
243 aDestination
.push_back(xRef
);
253 // add reference to result
254 aDestination
.push_back(xReference
);
261 // unknown implementation, add to result
262 aDestination
.push_back(xReference
);
267 // prepare return value
268 const sal_uInt32
nDestSize(aDestination
.size());
269 aRetval
.resize(nDestSize
);
271 for(sal_uInt32
b(0); b
< nDestSize
; b
++)
273 aRetval
[b
] = aDestination
[b
];
280 HatchTexturePrimitive3D::HatchTexturePrimitive3D(
281 const attribute::FillHatchAttribute
& rHatch
,
282 const Primitive3DContainer
& rChildren
,
283 const basegfx::B2DVector
& rTextureSize
,
286 : TexturePrimitive3D(rChildren
, rTextureSize
, bModulate
, bFilter
),
288 maBuffered3DDecomposition()
292 bool HatchTexturePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
294 if(TexturePrimitive3D::operator==(rPrimitive
))
296 const HatchTexturePrimitive3D
& rCompare
= static_cast<const HatchTexturePrimitive3D
&>(rPrimitive
);
298 return (getHatch() == rCompare
.getHatch());
304 Primitive3DContainer
HatchTexturePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& /*rViewInformation*/) const
306 ::osl::MutexGuard
aGuard( m_aMutex
);
308 if(getBuffered3DDecomposition().empty())
310 const Primitive3DContainer
aNewSequence(impCreate3DDecomposition());
311 const_cast< HatchTexturePrimitive3D
* >(this)->maBuffered3DDecomposition
= aNewSequence
;
314 return getBuffered3DDecomposition();
318 ImplPrimitive3DIDBlock(HatchTexturePrimitive3D
, PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D
)
320 } // end of namespace primitive3d
321 } // end of namespace drawinglayer
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */