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 <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 <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>
35 using namespace com::sun::star
;
38 namespace drawinglayer::primitive3d
40 Primitive3DContainer
HatchTexturePrimitive3D::impCreate3DDecomposition() const
42 Primitive3DContainer aRetval
;
44 if(!getChildren().empty())
46 const Primitive3DContainer
aSource(getChildren());
47 const size_t nSourceCount(aSource
.size());
48 std::vector
< Primitive3DReference
> aDestination
;
50 for(size_t a(0); a
< nSourceCount
; a
++)
53 const Primitive3DReference
& xReference(aSource
[a
]);
57 const BasePrimitive3D
* pBasePrimitive
= static_cast< const BasePrimitive3D
* >(xReference
.get());
59 // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
60 // not all content is needed, remove transparencies and ModifiedColorPrimitives
61 switch(pBasePrimitive
->getPrimitive3DID())
63 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D
:
65 // polyPolygonMaterialPrimitive3D, check texturing and hatching
66 const PolyPolygonMaterialPrimitive3D
& rPrimitive
= static_cast< const PolyPolygonMaterialPrimitive3D
& >(*pBasePrimitive
);
67 const basegfx::B3DPolyPolygon
& aFillPolyPolygon(rPrimitive
.getB3DPolyPolygon());
69 if(maHatch
.isFillBackground())
71 // add original primitive for background
72 aDestination
.push_back(xReference
);
75 if(aFillPolyPolygon
.areTextureCoordinatesUsed())
77 const sal_uInt32
nPolyCount(aFillPolyPolygon
.count());
78 basegfx::B2DPolyPolygon aTexPolyPolygon
;
79 basegfx::B2DPoint a2N
;
80 basegfx::B2DVector a2X
, a2Y
;
81 basegfx::B3DPoint a3N
;
82 basegfx::B3DVector a3X
, a3Y
;
83 bool b2N(false), b2X(false), b2Y(false);
85 for(sal_uInt32
b(0); b
< nPolyCount
; b
++)
87 const basegfx::B3DPolygon
& aPartPoly(aFillPolyPolygon
.getB3DPolygon(b
));
88 const sal_uInt32
nPointCount(aPartPoly
.count());
89 basegfx::B2DPolygon aTexPolygon
;
91 for(sal_uInt32
c(0); c
< nPointCount
; c
++)
93 const basegfx::B2DPoint
a2Candidate(aPartPoly
.getTextureCoordinate(c
));
98 a3N
= aPartPoly
.getB3DPoint(c
);
101 else if(!b2X
&& !a2N
.equal(a2Candidate
))
103 a2X
= a2Candidate
- a2N
;
104 a3X
= aPartPoly
.getB3DPoint(c
) - a3N
;
107 else if(!b2Y
&& !a2N
.equal(a2Candidate
) && !a2X
.equal(a2Candidate
))
109 a2Y
= a2Candidate
- a2N
;
111 const double fCross(a2X
.cross(a2Y
));
113 if(!basegfx::fTools::equalZero(fCross
))
115 a3Y
= aPartPoly
.getB3DPoint(c
) - a3N
;
120 aTexPolygon
.append(a2Candidate
);
123 aTexPolygon
.setClosed(true);
124 aTexPolyPolygon
.append(aTexPolygon
);
127 if(b2N
&& b2X
&& b2Y
)
129 // found two linearly independent 2D vectors
130 // get 2d range of texture coordinates
131 const basegfx::B2DRange
aOutlineRange(basegfx::utils::getRange(aTexPolyPolygon
));
132 const basegfx::BColor
aHatchColor(getHatch().getColor());
133 const double fAngle(getHatch().getAngle());
134 std::vector
< basegfx::B2DHomMatrix
> aMatrices
;
136 // get hatch transformations
137 switch(getHatch().getStyle())
139 case attribute::HatchStyle::Triple
:
141 // rotated 45 degrees
142 texture::GeoTexSvxHatch
aHatch(
145 getHatch().getDistance(),
148 aHatch
.appendTransformations(aMatrices
);
152 case attribute::HatchStyle::Double
:
154 // rotated 90 degrees
155 texture::GeoTexSvxHatch
aHatch(
158 getHatch().getDistance(),
161 aHatch
.appendTransformations(aMatrices
);
165 case attribute::HatchStyle::Single
:
168 texture::GeoTexSvxHatch
aHatch(
171 getHatch().getDistance(),
174 aHatch
.appendTransformations(aMatrices
);
178 // create geometry from unit line
179 basegfx::B2DPolyPolygon a2DHatchLines
;
180 basegfx::B2DPolygon a2DUnitLine
;
181 a2DUnitLine
.append(basegfx::B2DPoint(0.0, 0.0));
182 a2DUnitLine
.append(basegfx::B2DPoint(1.0, 0.0));
184 for(const basegfx::B2DHomMatrix
& rMatrix
: aMatrices
)
186 basegfx::B2DPolygon
aNewLine(a2DUnitLine
);
187 aNewLine
.transform(rMatrix
);
188 a2DHatchLines
.append(aNewLine
);
191 if(a2DHatchLines
.count())
193 // clip against texture polygon
194 a2DHatchLines
= basegfx::utils::clipPolyPolygonOnPolyPolygon(a2DHatchLines
, aTexPolyPolygon
, true, true);
197 if(a2DHatchLines
.count())
199 // create 2d matrix with 2d vectors as column vectors and 2d point as offset, this represents
200 // a coordinate system transformation from unit coordinates to the new coordinate system
201 basegfx::B2DHomMatrix a2D
;
202 a2D
.set(0, 0, a2X
.getX());
203 a2D
.set(1, 0, a2X
.getY());
204 a2D
.set(0, 1, a2Y
.getX());
205 a2D
.set(1, 1, a2Y
.getY());
206 a2D
.set(0, 2, a2N
.getX());
207 a2D
.set(1, 2, a2N
.getY());
209 // invert that transformation, so we have a back-transformation from texture coordinates
210 // to unit coordinates
212 a2DHatchLines
.transform(a2D
);
214 // expand back-transformed geometry to 3D
215 basegfx::B3DPolyPolygon
a3DHatchLines(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(a2DHatchLines
, 0.0));
217 // create 3d matrix with 3d vectors as column vectors (0,0,1 as Z) and 3d point as offset, this represents
218 // a coordinate system transformation from unit coordinates to the object's 3d coordinate system
219 basegfx::B3DHomMatrix a3D
;
220 a3D
.set(0, 0, a3X
.getX());
221 a3D
.set(1, 0, a3X
.getY());
222 a3D
.set(2, 0, a3X
.getZ());
223 a3D
.set(0, 1, a3Y
.getX());
224 a3D
.set(1, 1, a3Y
.getY());
225 a3D
.set(2, 1, a3Y
.getZ());
226 a3D
.set(0, 3, a3N
.getX());
227 a3D
.set(1, 3, a3N
.getY());
228 a3D
.set(2, 3, a3N
.getZ());
230 // transform hatch lines to 3D object coordinates
231 a3DHatchLines
.transform(a3D
);
233 // build primitives from this geometry
234 const sal_uInt32
nHatchLines(a3DHatchLines
.count());
236 for(sal_uInt32
d(0); d
< nHatchLines
; d
++)
238 const Primitive3DReference
xRef(new PolygonHairlinePrimitive3D(a3DHatchLines
.getB3DPolygon(d
), aHatchColor
));
239 aDestination
.push_back(xRef
);
249 // add reference to result
250 aDestination
.push_back(xReference
);
257 // prepare return value
258 const sal_uInt32
nDestSize(aDestination
.size());
259 aRetval
.resize(nDestSize
);
261 for(sal_uInt32
b(0); b
< nDestSize
; b
++)
263 aRetval
[b
] = aDestination
[b
];
270 HatchTexturePrimitive3D::HatchTexturePrimitive3D(
271 attribute::FillHatchAttribute aHatch
,
272 const Primitive3DContainer
& rChildren
,
273 const basegfx::B2DVector
& rTextureSize
,
276 : TexturePrimitive3D(rChildren
, rTextureSize
, bModulate
, bFilter
),
277 maHatch(std::move(aHatch
))
281 bool HatchTexturePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
283 if(TexturePrimitive3D::operator==(rPrimitive
))
285 const HatchTexturePrimitive3D
& rCompare
= static_cast<const HatchTexturePrimitive3D
&>(rPrimitive
);
287 return (getHatch() == rCompare
.getHatch());
293 Primitive3DContainer
HatchTexturePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& /*rViewInformation*/) const
295 std::unique_lock
aGuard( m_aMutex
);
297 if(getBuffered3DDecomposition().empty())
299 const Primitive3DContainer
aNewSequence(impCreate3DDecomposition());
300 const_cast< HatchTexturePrimitive3D
* >(this)->maBuffered3DDecomposition
= aNewSequence
;
303 return getBuffered3DDecomposition();
307 ImplPrimitive3DIDBlock(HatchTexturePrimitive3D
, PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D
)
309 } // end of namespace
311 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */