/src/libreoffice/drawinglayer/source/texture/texture.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include <algorithm> |
23 | | |
24 | | #include <texture/texture.hxx> |
25 | | #include <basegfx/numeric/ftools.hxx> |
26 | | #include <basegfx/utils/gradienttools.hxx> |
27 | | #include <basegfx/matrix/b2dhommatrixtools.hxx> |
28 | | |
29 | | #include <comphelper/random.hxx> |
30 | | |
31 | | namespace drawinglayer::texture |
32 | | { |
33 | | namespace |
34 | | { |
35 | | double getRandomColorRange() |
36 | 0 | { |
37 | 0 | return comphelper::rng::uniform_real_distribution(0.0, nextafter(1.0, DBL_MAX)); |
38 | 0 | } |
39 | | } |
40 | | |
41 | | GeoTexSvx::GeoTexSvx() |
42 | 0 | { |
43 | 0 | } |
44 | | |
45 | | GeoTexSvx::~GeoTexSvx() |
46 | 0 | { |
47 | 0 | } |
48 | | |
49 | | bool GeoTexSvx::operator==(const GeoTexSvx& /*rGeoTexSvx*/) const |
50 | 0 | { |
51 | | // default implementation says yes (no data -> no difference) |
52 | 0 | return true; |
53 | 0 | } |
54 | | |
55 | | void GeoTexSvx::modifyBColor(const basegfx::B2DPoint& /*rUV*/, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
56 | 0 | { |
57 | | // base implementation creates random color (for testing only, may also be pure virtual) |
58 | 0 | rBColor.setRed(getRandomColorRange()); |
59 | 0 | rBColor.setGreen(getRandomColorRange()); |
60 | 0 | rBColor.setBlue(getRandomColorRange()); |
61 | 0 | } |
62 | | |
63 | | void GeoTexSvx::modifyOpacity(const basegfx::B2DPoint& rUV, double& rfOpacity) const |
64 | 0 | { |
65 | | // base implementation uses inverse of luminance of solved color (for testing only, may also be pure virtual) |
66 | 0 | basegfx::BColor aBaseColor; |
67 | 0 | modifyBColor(rUV, aBaseColor, rfOpacity); |
68 | 0 | rfOpacity = 1.0 - aBaseColor.luminance(); |
69 | 0 | } |
70 | | |
71 | | |
72 | | GeoTexSvxGradient::GeoTexSvxGradient( |
73 | | const basegfx::B2DRange& rDefinitionRange, |
74 | | sal_uInt32 nRequestedSteps, |
75 | | const basegfx::BColorStops& rColorStops, |
76 | | double fBorder) |
77 | 0 | : maDefinitionRange(rDefinitionRange) |
78 | 0 | , mnRequestedSteps(nRequestedSteps) |
79 | 0 | , mnColorStops(rColorStops) |
80 | 0 | , mfBorder(fBorder) |
81 | 0 | , maLastColorStopRange() |
82 | 0 | { |
83 | 0 | } |
84 | | |
85 | | GeoTexSvxGradient::~GeoTexSvxGradient() |
86 | 0 | { |
87 | 0 | } |
88 | | |
89 | | bool GeoTexSvxGradient::operator==(const GeoTexSvx& rGeoTexSvx) const |
90 | 0 | { |
91 | 0 | const GeoTexSvxGradient* pCompare = dynamic_cast< const GeoTexSvxGradient* >(&rGeoTexSvx); |
92 | |
|
93 | 0 | return (pCompare |
94 | 0 | && maGradientInfo == pCompare->maGradientInfo |
95 | 0 | && maDefinitionRange == pCompare->maDefinitionRange |
96 | 0 | && mnRequestedSteps == pCompare->mnRequestedSteps |
97 | 0 | && mnColorStops == pCompare->mnColorStops |
98 | 0 | && mfBorder == pCompare->mfBorder); |
99 | 0 | } |
100 | | |
101 | | GeoTexSvxGradientLinear::GeoTexSvxGradientLinear( |
102 | | const basegfx::B2DRange& rDefinitionRange, |
103 | | const basegfx::B2DRange& rOutputRange, |
104 | | sal_uInt32 nRequestedSteps, |
105 | | const basegfx::BColorStops& rColorStops, |
106 | | double fBorder, |
107 | | double fAngle) |
108 | 0 | : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorStops, fBorder) |
109 | 0 | , mfUnitMinX(0.0) |
110 | 0 | , mfUnitWidth(1.0) |
111 | 0 | , mfUnitMaxY(1.0) |
112 | 0 | { |
113 | 0 | maGradientInfo = basegfx::utils::createLinearODFGradientInfo( |
114 | 0 | rDefinitionRange, |
115 | 0 | nRequestedSteps, |
116 | 0 | fBorder, |
117 | 0 | fAngle); |
118 | |
|
119 | 0 | if(rDefinitionRange != rOutputRange) |
120 | 0 | { |
121 | 0 | basegfx::B2DRange aInvOutputRange(rOutputRange); |
122 | |
|
123 | 0 | aInvOutputRange.transform(maGradientInfo.getBackTextureTransform()); |
124 | 0 | mfUnitMinX = aInvOutputRange.getMinX(); |
125 | 0 | mfUnitWidth = aInvOutputRange.getWidth(); |
126 | 0 | mfUnitMaxY = aInvOutputRange.getMaxY(); |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | GeoTexSvxGradientLinear::~GeoTexSvxGradientLinear() |
131 | | { |
132 | | } |
133 | | |
134 | | void GeoTexSvxGradientLinear::appendTransformationsAndColors( |
135 | | const std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)>& rCallback) |
136 | 0 | { |
137 | | // no color at all, done |
138 | 0 | if (mnColorStops.empty()) |
139 | 0 | return; |
140 | | |
141 | | // only one color, done |
142 | 0 | if (mnColorStops.size() < 2) |
143 | 0 | return; |
144 | | |
145 | | // check if we need last-ColorStop-correction |
146 | 0 | const bool bPenultimateUsed(mnColorStops.checkPenultimate()); |
147 | |
|
148 | 0 | if (bPenultimateUsed) |
149 | 0 | { |
150 | | // Here we need to temporarily add a ColorStop entry with the |
151 | | // same color as the last entry to correctly 'close' the |
152 | | // created gradient geometry. |
153 | | // The simplest way is to temporarily add an entry to the local |
154 | | // ColorStops for this at 1.0 (using same color) |
155 | 0 | mnColorStops.emplace_back(1.0, mnColorStops.back().getStopColor()); |
156 | 0 | } |
157 | | |
158 | | // prepare unit range transform |
159 | 0 | basegfx::B2DHomMatrix aPattern; |
160 | | |
161 | | // bring from unit circle [-1, -1, 1, 1] to unit range [0, 0, 1, 1] |
162 | 0 | aPattern.scale(0.5, 0.5); |
163 | 0 | aPattern.translate(0.5, 0.5); |
164 | | |
165 | | // scale and translate in X |
166 | 0 | aPattern.scale(mfUnitWidth, 1.0); |
167 | 0 | aPattern.translate(mfUnitMinX, 0.0); |
168 | | |
169 | | // outer loop over ColorStops, each is from cs_l to cs_r |
170 | 0 | for (auto cs_l(mnColorStops.begin()), cs_r(cs_l + 1); cs_r != mnColorStops.end(); cs_l++, cs_r++) |
171 | 0 | { |
172 | | // get offsets |
173 | 0 | const double fOffsetStart(cs_l->getStopOffset()); |
174 | 0 | const double fOffsetEnd(cs_r->getStopOffset()); |
175 | | |
176 | | // same offset, empty BColorStopRange, continue with next step |
177 | 0 | if (basegfx::fTools::equal(fOffsetStart, fOffsetEnd)) |
178 | 0 | continue; |
179 | | |
180 | | // get colors & calculate steps |
181 | 0 | const basegfx::BColor aCStart(cs_l->getStopColor()); |
182 | 0 | const basegfx::BColor aCEnd(cs_r->getStopColor()); |
183 | 0 | const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( |
184 | 0 | maGradientInfo.getRequestedSteps(), aCStart, aCEnd)); |
185 | | |
186 | | // calculate StripeWidth |
187 | | // nSteps is >= 1, see getRequestedSteps, so no check needed here |
188 | 0 | const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); |
189 | | |
190 | | // for the 1st color range we do not need to create the 1st step |
191 | | // since it will be equal to StartColor and thus OuterColor, so |
192 | | // will be painted by the 1st, always-created background polygon |
193 | | // colored using OuterColor. |
194 | | // We *need* to create this though for all 'inner' color ranges |
195 | | // to get a correct start |
196 | 0 | const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); |
197 | |
|
198 | 0 | for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++) |
199 | 0 | { |
200 | | // calculate pos in Y |
201 | 0 | const double fPos(fOffsetStart + (fStripeWidth * innerLoop)); |
202 | | |
203 | | // scale and translate in Y. For GradientLinear we always have |
204 | | // the full height |
205 | 0 | double fHeight(1.0 - fPos); |
206 | |
|
207 | 0 | if (mfUnitMaxY > 1.0) |
208 | 0 | { |
209 | | // extend when difference between definition and OutputRange exists |
210 | 0 | fHeight += mfUnitMaxY - 1.0; |
211 | 0 | } |
212 | |
|
213 | 0 | basegfx::B2DHomMatrix aNew(aPattern); |
214 | 0 | aNew.scale(1.0, fHeight); |
215 | 0 | aNew.translate(0.0, fPos); |
216 | | |
217 | | // set and add at target |
218 | 0 | rCallback( |
219 | 0 | maGradientInfo.getTextureTransform() * aNew, |
220 | 0 | 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); |
221 | 0 | } |
222 | 0 | } |
223 | |
|
224 | 0 | if (bPenultimateUsed) |
225 | 0 | { |
226 | | // correct temporary change |
227 | 0 | mnColorStops.pop_back(); |
228 | 0 | } |
229 | 0 | } |
230 | | |
231 | | void GeoTexSvxGradientLinear::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
232 | 0 | { |
233 | | // no color at all, done |
234 | 0 | if (mnColorStops.empty()) |
235 | 0 | return; |
236 | | |
237 | | // just single color, done |
238 | 0 | if (mnColorStops.size() < 2) |
239 | 0 | { |
240 | 0 | rBColor = mnColorStops.front().getStopColor(); |
241 | 0 | return; |
242 | 0 | } |
243 | | |
244 | | // texture-back-transform X/Y -> t [0.0..1.0] and determine color |
245 | 0 | const double fScaler(basegfx::utils::getLinearGradientAlpha(rUV, maGradientInfo)); |
246 | 0 | rBColor = mnColorStops.getInterpolatedBColor(fScaler, mnRequestedSteps, maLastColorStopRange); |
247 | 0 | } |
248 | | |
249 | | GeoTexSvxGradientAxial::GeoTexSvxGradientAxial( |
250 | | const basegfx::B2DRange& rDefinitionRange, |
251 | | const basegfx::B2DRange& rOutputRange, |
252 | | sal_uInt32 nRequestedSteps, |
253 | | const basegfx::BColorStops& rColorStops, |
254 | | double fBorder, |
255 | | double fAngle) |
256 | 0 | : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorStops, fBorder) |
257 | 0 | , mfUnitMinX(0.0) |
258 | 0 | , mfUnitWidth(1.0) |
259 | 0 | { |
260 | | // ARGH! GradientAxial uses the ColorStops in reverse order compared |
261 | | // with the other gradients. Either stay 'thinking reverse' for the |
262 | | // rest of time or adapt it here and go in same order as the other five, |
263 | | // so unifications/tooling will be possible |
264 | 0 | mnColorStops.reverseColorStops(); |
265 | |
|
266 | 0 | maGradientInfo = basegfx::utils::createAxialODFGradientInfo( |
267 | 0 | rDefinitionRange, |
268 | 0 | nRequestedSteps, |
269 | 0 | fBorder, |
270 | 0 | fAngle); |
271 | |
|
272 | 0 | if(rDefinitionRange != rOutputRange) |
273 | 0 | { |
274 | 0 | basegfx::B2DRange aInvOutputRange(rOutputRange); |
275 | |
|
276 | 0 | aInvOutputRange.transform(maGradientInfo.getBackTextureTransform()); |
277 | 0 | mfUnitMinX = aInvOutputRange.getMinX(); |
278 | 0 | mfUnitWidth = aInvOutputRange.getWidth(); |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | | GeoTexSvxGradientAxial::~GeoTexSvxGradientAxial() |
283 | | { |
284 | | } |
285 | | |
286 | | void GeoTexSvxGradientAxial::appendTransformationsAndColors( |
287 | | const std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)>& rCallback) |
288 | 0 | { |
289 | | // no color at all, done |
290 | 0 | if (mnColorStops.empty()) |
291 | 0 | return; |
292 | | |
293 | | // only one color, done |
294 | 0 | if (mnColorStops.size() < 2) |
295 | 0 | return; |
296 | | |
297 | | // check if we need last-ColorStop-correction |
298 | 0 | const bool bPenultimateUsed(mnColorStops.checkPenultimate()); |
299 | |
|
300 | 0 | if (bPenultimateUsed) |
301 | 0 | { |
302 | | // temporarily add a ColorStop entry |
303 | 0 | mnColorStops.emplace_back(1.0, mnColorStops.back().getStopColor()); |
304 | 0 | } |
305 | | |
306 | | // prepare unit range transform |
307 | 0 | basegfx::B2DHomMatrix aPattern; |
308 | | |
309 | | // bring in X from unit circle [-1, -1, 1, 1] to unit range [0, 0, 1, 1] |
310 | 0 | aPattern.scale(0.5, 1.0); |
311 | 0 | aPattern.translate(0.5, 0.0); |
312 | | |
313 | | // scale/translate in X |
314 | 0 | aPattern.scale(mfUnitWidth, 1.0); |
315 | 0 | aPattern.translate(mfUnitMinX, 0.0); |
316 | | |
317 | | // outer loop over ColorStops, each is from cs_l to cs_r |
318 | 0 | for (auto cs_l(mnColorStops.begin()), cs_r(cs_l + 1); cs_r != mnColorStops.end(); cs_l++, cs_r++) |
319 | 0 | { |
320 | | // get offsets |
321 | 0 | const double fOffsetStart(cs_l->getStopOffset()); |
322 | 0 | const double fOffsetEnd(cs_r->getStopOffset()); |
323 | | |
324 | | // same offset, empty BColorStopRange, continue with next step |
325 | 0 | if (basegfx::fTools::equal(fOffsetStart, fOffsetEnd)) |
326 | 0 | continue; |
327 | | |
328 | | // get colors & calculate steps |
329 | 0 | const basegfx::BColor aCStart(cs_l->getStopColor()); |
330 | 0 | const basegfx::BColor aCEnd(cs_r->getStopColor()); |
331 | 0 | const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( |
332 | 0 | maGradientInfo.getRequestedSteps(), aCStart, aCEnd)); |
333 | | |
334 | | // calculate StripeWidth |
335 | | // nSteps is >= 1, see getRequestedSteps, so no check needed here |
336 | 0 | const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); |
337 | | |
338 | | // for the 1st color range we do not need to create the 1st step, see above |
339 | 0 | const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); |
340 | |
|
341 | 0 | for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++) |
342 | 0 | { |
343 | | // calculate pos in Y |
344 | 0 | const double fPos(fOffsetStart + (fStripeWidth * innerLoop)); |
345 | | |
346 | | // already centered in Y on X-Axis, just scale in Y |
347 | 0 | basegfx::B2DHomMatrix aNew(aPattern); |
348 | 0 | aNew.scale(1.0, 1.0 - fPos); |
349 | | |
350 | | // set and add at target |
351 | 0 | rCallback( |
352 | 0 | maGradientInfo.getTextureTransform() * aNew, |
353 | 0 | 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); |
354 | 0 | } |
355 | 0 | } |
356 | |
|
357 | 0 | if (bPenultimateUsed) |
358 | 0 | { |
359 | | // correct temporary change |
360 | 0 | mnColorStops.pop_back(); |
361 | 0 | } |
362 | 0 | } |
363 | | |
364 | | void GeoTexSvxGradientAxial::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
365 | 0 | { |
366 | | // no color at all, done |
367 | 0 | if (mnColorStops.empty()) |
368 | 0 | return; |
369 | | |
370 | | // just single color, done |
371 | 0 | if (mnColorStops.size() < 2) |
372 | 0 | { |
373 | | // we use the reverse ColorSteps here, so use front value |
374 | 0 | rBColor = mnColorStops.front().getStopColor(); |
375 | 0 | return; |
376 | 0 | } |
377 | | |
378 | | // texture-back-transform X/Y -> t [0.0..1.0] and determine color |
379 | 0 | const double fScaler(basegfx::utils::getAxialGradientAlpha(rUV, maGradientInfo)); |
380 | | |
381 | | // we use the reverse ColorSteps here, so mirror scaler value |
382 | 0 | rBColor = mnColorStops.getInterpolatedBColor(1.0 - fScaler, mnRequestedSteps, maLastColorStopRange); |
383 | 0 | } |
384 | | |
385 | | |
386 | | GeoTexSvxGradientRadial::GeoTexSvxGradientRadial( |
387 | | const basegfx::B2DRange& rDefinitionRange, |
388 | | sal_uInt32 nRequestedSteps, |
389 | | const basegfx::BColorStops& rColorStops, |
390 | | double fBorder, |
391 | | double fOffsetX, |
392 | | double fOffsetY) |
393 | 0 | : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorStops, fBorder) |
394 | 0 | { |
395 | 0 | maGradientInfo = basegfx::utils::createRadialODFGradientInfo( |
396 | 0 | rDefinitionRange, |
397 | 0 | basegfx::B2DVector(fOffsetX,fOffsetY), |
398 | 0 | nRequestedSteps, |
399 | 0 | fBorder); |
400 | 0 | } |
401 | | |
402 | | GeoTexSvxGradientRadial::~GeoTexSvxGradientRadial() |
403 | | { |
404 | | } |
405 | | |
406 | | void GeoTexSvxGradientRadial::appendTransformationsAndColors( |
407 | | const std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)>& rCallback) |
408 | 0 | { |
409 | | // no color at all, done |
410 | 0 | if (mnColorStops.empty()) |
411 | 0 | return; |
412 | | |
413 | | // only one color, done |
414 | 0 | if (mnColorStops.size() < 2) |
415 | 0 | return; |
416 | | |
417 | | // check if we need last-ColorStop-correction |
418 | 0 | const bool bPenultimateUsed(mnColorStops.checkPenultimate()); |
419 | |
|
420 | 0 | if (bPenultimateUsed) |
421 | 0 | { |
422 | | // temporarily add a ColorStop entry |
423 | 0 | mnColorStops.emplace_back(1.0, mnColorStops.back().getStopColor()); |
424 | 0 | } |
425 | | |
426 | | // outer loop over ColorStops, each is from cs_l to cs_r |
427 | 0 | for (auto cs_l(mnColorStops.begin()), cs_r(cs_l + 1); cs_r != mnColorStops.end(); cs_l++, cs_r++) |
428 | 0 | { |
429 | | // get offsets |
430 | 0 | const double fOffsetStart(cs_l->getStopOffset()); |
431 | 0 | const double fOffsetEnd(cs_r->getStopOffset()); |
432 | | |
433 | | // same offset, empty BColorStopRange, continue with next step |
434 | 0 | if (basegfx::fTools::equal(fOffsetStart, fOffsetEnd)) |
435 | 0 | continue; |
436 | | |
437 | | // get colors & calculate steps |
438 | 0 | const basegfx::BColor aCStart(cs_l->getStopColor()); |
439 | 0 | const basegfx::BColor aCEnd(cs_r->getStopColor()); |
440 | 0 | const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( |
441 | 0 | maGradientInfo.getRequestedSteps(), aCStart, aCEnd)); |
442 | | |
443 | | // calculate StripeWidth |
444 | 0 | const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); |
445 | | |
446 | | // get correct start for inner loop (see above) |
447 | 0 | const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); |
448 | |
|
449 | 0 | for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++) |
450 | 0 | { |
451 | | // calculate size/radius |
452 | 0 | const double fSize(1.0 - (fOffsetStart + (fStripeWidth * innerLoop))); |
453 | | |
454 | | // set and add at target |
455 | 0 | rCallback( |
456 | 0 | maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize), |
457 | 0 | 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); |
458 | 0 | } |
459 | 0 | } |
460 | |
|
461 | 0 | if (bPenultimateUsed) |
462 | 0 | { |
463 | | // correct temporary change |
464 | 0 | mnColorStops.pop_back(); |
465 | 0 | } |
466 | 0 | } |
467 | | |
468 | | void GeoTexSvxGradientRadial::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
469 | 0 | { |
470 | | // no color at all, done |
471 | 0 | if (mnColorStops.empty()) |
472 | 0 | return; |
473 | | |
474 | | // just single color, done |
475 | 0 | if (mnColorStops.size() < 2) |
476 | 0 | { |
477 | 0 | rBColor = mnColorStops.front().getStopColor(); |
478 | 0 | return; |
479 | 0 | } |
480 | | |
481 | | // texture-back-transform X/Y -> t [0.0..1.0] and determine color |
482 | 0 | const double fScaler(basegfx::utils::getRadialGradientAlpha(rUV, maGradientInfo)); |
483 | 0 | rBColor = mnColorStops.getInterpolatedBColor(fScaler, mnRequestedSteps, maLastColorStopRange); |
484 | 0 | } |
485 | | |
486 | | |
487 | | GeoTexSvxGradientElliptical::GeoTexSvxGradientElliptical( |
488 | | const basegfx::B2DRange& rDefinitionRange, |
489 | | sal_uInt32 nRequestedSteps, |
490 | | const basegfx::BColorStops& rColorStops, |
491 | | double fBorder, |
492 | | double fOffsetX, |
493 | | double fOffsetY, |
494 | | double fAngle) |
495 | 0 | : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorStops, fBorder) |
496 | 0 | { |
497 | 0 | maGradientInfo = basegfx::utils::createEllipticalODFGradientInfo( |
498 | 0 | rDefinitionRange, |
499 | 0 | basegfx::B2DVector(fOffsetX,fOffsetY), |
500 | 0 | nRequestedSteps, |
501 | 0 | fBorder, |
502 | 0 | fAngle); |
503 | 0 | } |
504 | | |
505 | | GeoTexSvxGradientElliptical::~GeoTexSvxGradientElliptical() |
506 | | { |
507 | | } |
508 | | |
509 | | void GeoTexSvxGradientElliptical::appendTransformationsAndColors( |
510 | | const std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)>& rCallback) |
511 | 0 | { |
512 | | // no color at all, done |
513 | 0 | if (mnColorStops.empty()) |
514 | 0 | return; |
515 | | |
516 | | // only one color, done |
517 | 0 | if (mnColorStops.size() < 2) |
518 | 0 | return; |
519 | | |
520 | | // check if we need last-ColorStop-correction |
521 | 0 | const bool bPenultimateUsed(mnColorStops.checkPenultimate()); |
522 | |
|
523 | 0 | if (bPenultimateUsed) |
524 | 0 | { |
525 | | // temporarily add a ColorStop entry |
526 | 0 | mnColorStops.emplace_back(1.0, mnColorStops.back().getStopColor()); |
527 | 0 | } |
528 | | |
529 | | // prepare vars dependent on aspect ratio |
530 | 0 | const double fAR(maGradientInfo.getAspectRatio()); |
531 | 0 | const bool bMTO(fAR > 1.0); |
532 | | |
533 | | // outer loop over ColorStops, each is from cs_l to cs_r |
534 | 0 | for (auto cs_l(mnColorStops.begin()), cs_r(cs_l + 1); cs_r != mnColorStops.end(); cs_l++, cs_r++) |
535 | 0 | { |
536 | | // get offsets |
537 | 0 | const double fOffsetStart(cs_l->getStopOffset()); |
538 | 0 | const double fOffsetEnd(cs_r->getStopOffset()); |
539 | | |
540 | | // same offset, empty BColorStopRange, continue with next step |
541 | 0 | if (basegfx::fTools::equal(fOffsetStart, fOffsetEnd)) |
542 | 0 | continue; |
543 | | |
544 | | // get colors & calculate steps |
545 | 0 | const basegfx::BColor aCStart(cs_l->getStopColor()); |
546 | 0 | const basegfx::BColor aCEnd(cs_r->getStopColor()); |
547 | 0 | const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( |
548 | 0 | maGradientInfo.getRequestedSteps(), aCStart, aCEnd)); |
549 | | |
550 | | // calculate StripeWidth |
551 | 0 | const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); |
552 | | |
553 | | // get correct start for inner loop (see above) |
554 | 0 | const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); |
555 | |
|
556 | 0 | for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++) |
557 | 0 | { |
558 | | // calculate offset position for entry |
559 | 0 | const double fSize(fOffsetStart + (fStripeWidth * innerLoop)); |
560 | | |
561 | | // set and add at target |
562 | 0 | rCallback( |
563 | 0 | maGradientInfo.getTextureTransform() |
564 | 0 | * basegfx::utils::createScaleB2DHomMatrix( |
565 | 0 | 1.0 - (bMTO ? fSize / fAR : fSize), |
566 | 0 | 1.0 - (bMTO ? fSize : fSize * fAR)), |
567 | 0 | 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); |
568 | 0 | } |
569 | 0 | } |
570 | |
|
571 | 0 | if (bPenultimateUsed) |
572 | 0 | { |
573 | | // correct temporary change |
574 | 0 | mnColorStops.pop_back(); |
575 | 0 | } |
576 | 0 | } |
577 | | |
578 | | void GeoTexSvxGradientElliptical::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
579 | 0 | { |
580 | | // no color at all, done |
581 | 0 | if (mnColorStops.empty()) |
582 | 0 | return; |
583 | | |
584 | | // just single color, done |
585 | 0 | if (mnColorStops.size() < 2) |
586 | 0 | { |
587 | 0 | rBColor = mnColorStops.front().getStopColor(); |
588 | 0 | return; |
589 | 0 | } |
590 | | |
591 | | // texture-back-transform X/Y -> t [0.0..1.0] and determine color |
592 | 0 | const double fScaler(basegfx::utils::getEllipticalGradientAlpha(rUV, maGradientInfo)); |
593 | 0 | rBColor = mnColorStops.getInterpolatedBColor(fScaler, mnRequestedSteps, maLastColorStopRange); |
594 | 0 | } |
595 | | |
596 | | |
597 | | GeoTexSvxGradientSquare::GeoTexSvxGradientSquare( |
598 | | const basegfx::B2DRange& rDefinitionRange, |
599 | | sal_uInt32 nRequestedSteps, |
600 | | const basegfx::BColorStops& rColorStops, |
601 | | double fBorder, |
602 | | double fOffsetX, |
603 | | double fOffsetY, |
604 | | double fAngle) |
605 | 0 | : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorStops, fBorder) |
606 | 0 | { |
607 | 0 | maGradientInfo = basegfx::utils::createSquareODFGradientInfo( |
608 | 0 | rDefinitionRange, |
609 | 0 | basegfx::B2DVector(fOffsetX,fOffsetY), |
610 | 0 | nRequestedSteps, |
611 | 0 | fBorder, |
612 | 0 | fAngle); |
613 | 0 | } |
614 | | |
615 | | GeoTexSvxGradientSquare::~GeoTexSvxGradientSquare() |
616 | | { |
617 | | } |
618 | | |
619 | | void GeoTexSvxGradientSquare::appendTransformationsAndColors( |
620 | | const std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)>& rCallback) |
621 | 0 | { |
622 | | // no color at all, done |
623 | 0 | if (mnColorStops.empty()) |
624 | 0 | return; |
625 | | |
626 | | // only one color, done |
627 | 0 | if (mnColorStops.size() < 2) |
628 | 0 | return; |
629 | | |
630 | | // check if we need last-ColorStop-correction |
631 | 0 | const bool bPenultimateUsed(mnColorStops.checkPenultimate()); |
632 | |
|
633 | 0 | if (bPenultimateUsed) |
634 | 0 | { |
635 | | // temporarily add a ColorStop entry |
636 | 0 | mnColorStops.emplace_back(1.0, mnColorStops.back().getStopColor()); |
637 | 0 | } |
638 | | |
639 | | // outer loop over ColorStops, each is from cs_l to cs_r |
640 | 0 | for (auto cs_l(mnColorStops.begin()), cs_r(cs_l + 1); cs_r != mnColorStops.end(); cs_l++, cs_r++) |
641 | 0 | { |
642 | | // get offsets |
643 | 0 | const double fOffsetStart(cs_l->getStopOffset()); |
644 | 0 | const double fOffsetEnd(cs_r->getStopOffset()); |
645 | | |
646 | | // same offset, empty BColorStopRange, continue with next step |
647 | 0 | if (basegfx::fTools::equal(fOffsetStart, fOffsetEnd)) |
648 | 0 | continue; |
649 | | |
650 | | // get colors & calculate steps |
651 | 0 | const basegfx::BColor aCStart(cs_l->getStopColor()); |
652 | 0 | const basegfx::BColor aCEnd(cs_r->getStopColor()); |
653 | 0 | const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( |
654 | 0 | maGradientInfo.getRequestedSteps(), aCStart, aCEnd)); |
655 | | |
656 | | // calculate StripeWidth |
657 | 0 | const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); |
658 | | |
659 | | // get correct start for inner loop (see above) |
660 | 0 | const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); |
661 | |
|
662 | 0 | for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++) |
663 | 0 | { |
664 | | // calculate size/radius |
665 | 0 | const double fSize(1.0 - (fOffsetStart + (fStripeWidth * innerLoop))); |
666 | | |
667 | | // set and add at target |
668 | 0 | rCallback( |
669 | 0 | maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize), |
670 | 0 | 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); |
671 | 0 | } |
672 | 0 | } |
673 | |
|
674 | 0 | if (bPenultimateUsed) |
675 | 0 | { |
676 | | // correct temporary change |
677 | 0 | mnColorStops.pop_back(); |
678 | 0 | } |
679 | 0 | } |
680 | | |
681 | | void GeoTexSvxGradientSquare::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
682 | 0 | { |
683 | | // no color at all, done |
684 | 0 | if (mnColorStops.empty()) |
685 | 0 | return; |
686 | | |
687 | | // just single color, done |
688 | 0 | if (mnColorStops.size() < 2) |
689 | 0 | { |
690 | 0 | rBColor = mnColorStops.front().getStopColor(); |
691 | 0 | return; |
692 | 0 | } |
693 | | |
694 | | // texture-back-transform X/Y -> t [0.0..1.0] and determine color |
695 | 0 | const double fScaler(basegfx::utils::getSquareGradientAlpha(rUV, maGradientInfo)); |
696 | 0 | rBColor = mnColorStops.getInterpolatedBColor(fScaler, mnRequestedSteps, maLastColorStopRange); |
697 | 0 | } |
698 | | |
699 | | |
700 | | GeoTexSvxGradientRect::GeoTexSvxGradientRect( |
701 | | const basegfx::B2DRange& rDefinitionRange, |
702 | | sal_uInt32 nRequestedSteps, |
703 | | const basegfx::BColorStops& rColorStops, |
704 | | double fBorder, |
705 | | double fOffsetX, |
706 | | double fOffsetY, |
707 | | double fAngle) |
708 | 0 | : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorStops, fBorder) |
709 | 0 | { |
710 | 0 | maGradientInfo = basegfx::utils::createRectangularODFGradientInfo( |
711 | 0 | rDefinitionRange, |
712 | 0 | basegfx::B2DVector(fOffsetX,fOffsetY), |
713 | 0 | nRequestedSteps, |
714 | 0 | fBorder, |
715 | 0 | fAngle); |
716 | 0 | } |
717 | | |
718 | | GeoTexSvxGradientRect::~GeoTexSvxGradientRect() |
719 | | { |
720 | | } |
721 | | |
722 | | void GeoTexSvxGradientRect::appendTransformationsAndColors( |
723 | | const std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)>& rCallback) |
724 | 0 | { |
725 | | // no color at all, done |
726 | 0 | if (mnColorStops.empty()) |
727 | 0 | return; |
728 | | |
729 | | // only one color, done |
730 | 0 | if (mnColorStops.size() < 2) |
731 | 0 | return; |
732 | | |
733 | | // check if we need last-ColorStop-correction |
734 | 0 | const bool bPenultimateUsed(mnColorStops.checkPenultimate()); |
735 | |
|
736 | 0 | if (bPenultimateUsed) |
737 | 0 | { |
738 | | // temporarily add a ColorStop entry |
739 | 0 | mnColorStops.emplace_back(1.0, mnColorStops.back().getStopColor()); |
740 | 0 | } |
741 | | |
742 | | // prepare vars dependent on aspect ratio |
743 | 0 | const double fAR(maGradientInfo.getAspectRatio()); |
744 | 0 | const bool bMTO(fAR > 1.0); |
745 | | |
746 | | // outer loop over ColorStops, each is from cs_l to cs_r |
747 | 0 | for (auto cs_l(mnColorStops.begin()), cs_r(cs_l + 1); cs_r != mnColorStops.end(); cs_l++, cs_r++) |
748 | 0 | { |
749 | | // get offsets |
750 | 0 | const double fOffsetStart(cs_l->getStopOffset()); |
751 | 0 | const double fOffsetEnd(cs_r->getStopOffset()); |
752 | | |
753 | | // same offset, empty BColorStopRange, continue with next step |
754 | 0 | if (basegfx::fTools::equal(fOffsetStart, fOffsetEnd)) |
755 | 0 | continue; |
756 | | |
757 | | // get colors & calculate steps |
758 | 0 | const basegfx::BColor aCStart(cs_l->getStopColor()); |
759 | 0 | const basegfx::BColor aCEnd(cs_r->getStopColor()); |
760 | 0 | const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps( |
761 | 0 | maGradientInfo.getRequestedSteps(), aCStart, aCEnd)); |
762 | | |
763 | | // calculate StripeWidth |
764 | 0 | const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); |
765 | | |
766 | | // get correct start for inner loop (see above) |
767 | 0 | const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); |
768 | |
|
769 | 0 | for (sal_uInt32 innerLoop(nStartInnerLoop); innerLoop < nSteps; innerLoop++) |
770 | 0 | { |
771 | | // calculate offset position for entry |
772 | 0 | const double fSize(fOffsetStart + (fStripeWidth * innerLoop)); |
773 | | |
774 | | // set and add at target |
775 | 0 | rCallback( |
776 | 0 | maGradientInfo.getTextureTransform() |
777 | 0 | * basegfx::utils::createScaleB2DHomMatrix( |
778 | 0 | 1.0 - (bMTO ? fSize / fAR : fSize), |
779 | 0 | 1.0 - (bMTO ? fSize : fSize * fAR)), |
780 | 0 | 1 == nSteps ? aCStart : basegfx::BColor(interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)))); |
781 | 0 | } |
782 | 0 | } |
783 | |
|
784 | 0 | if (bPenultimateUsed) |
785 | 0 | { |
786 | | // correct temporary change |
787 | 0 | mnColorStops.pop_back(); |
788 | 0 | } |
789 | 0 | } |
790 | | |
791 | | void GeoTexSvxGradientRect::modifyBColor(const basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const |
792 | 0 | { |
793 | | // no color at all, done |
794 | 0 | if (mnColorStops.empty()) |
795 | 0 | return; |
796 | | |
797 | | // just single color, done |
798 | 0 | if (mnColorStops.size() < 2) |
799 | 0 | { |
800 | 0 | rBColor = mnColorStops.front().getStopColor(); |
801 | 0 | return; |
802 | 0 | } |
803 | | |
804 | | // texture-back-transform X/Y -> t [0.0..1.0] and determine color |
805 | 0 | const double fScaler(basegfx::utils::getRectangularGradientAlpha(rUV, maGradientInfo)); |
806 | 0 | rBColor = mnColorStops.getInterpolatedBColor(fScaler, mnRequestedSteps, maLastColorStopRange); |
807 | 0 | } |
808 | | |
809 | | |
810 | | GeoTexSvxHatch::GeoTexSvxHatch( |
811 | | const basegfx::B2DRange& rDefinitionRange, |
812 | | const basegfx::B2DRange& rOutputRange, |
813 | | double fDistance, |
814 | | double fAngle) |
815 | 0 | : maOutputRange(rOutputRange), |
816 | 0 | mfDistance(0.1), |
817 | 0 | mfAngle(fAngle), |
818 | 0 | mnSteps(10), |
819 | 0 | mbDefinitionRangeEqualsOutputRange(rDefinitionRange == rOutputRange) |
820 | 0 | { |
821 | 0 | double fTargetSizeX(rDefinitionRange.getWidth()); |
822 | 0 | double fTargetSizeY(rDefinitionRange.getHeight()); |
823 | 0 | double fTargetOffsetX(rDefinitionRange.getMinX()); |
824 | 0 | double fTargetOffsetY(rDefinitionRange.getMinY()); |
825 | |
|
826 | 0 | fAngle = -fAngle; |
827 | | |
828 | | // add object expansion |
829 | 0 | if(0.0 != fAngle) |
830 | 0 | { |
831 | 0 | const double fAbsCos(fabs(cos(fAngle))); |
832 | 0 | const double fAbsSin(fabs(sin(fAngle))); |
833 | 0 | const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin); |
834 | 0 | const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin); |
835 | 0 | fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0; |
836 | 0 | fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0; |
837 | 0 | fTargetSizeX = fNewX; |
838 | 0 | fTargetSizeY = fNewY; |
839 | 0 | } |
840 | | |
841 | | // add object scale before rotate |
842 | 0 | maTextureTransform.scale(fTargetSizeX, fTargetSizeY); |
843 | | |
844 | | // add texture rotate after scale to keep perpendicular angles |
845 | 0 | if(0.0 != fAngle) |
846 | 0 | { |
847 | 0 | basegfx::B2DPoint aCenter(0.5, 0.5); |
848 | 0 | aCenter *= maTextureTransform; |
849 | |
|
850 | 0 | maTextureTransform = basegfx::utils::createRotateAroundPoint(aCenter, fAngle) |
851 | 0 | * maTextureTransform; |
852 | 0 | } |
853 | | |
854 | | // add object translate |
855 | 0 | maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY); |
856 | | |
857 | | // prepare height for texture |
858 | 0 | const double fSteps((0.0 != fDistance) ? fTargetSizeY / fDistance : 10.0); |
859 | 0 | mnSteps = basegfx::fround(fSteps + 0.5); |
860 | 0 | mfDistance = 1.0 / fSteps; |
861 | 0 | } |
862 | | |
863 | | GeoTexSvxHatch::~GeoTexSvxHatch() |
864 | | { |
865 | | } |
866 | | |
867 | | bool GeoTexSvxHatch::operator==(const GeoTexSvx& rGeoTexSvx) const |
868 | 0 | { |
869 | 0 | const GeoTexSvxHatch* pCompare = dynamic_cast< const GeoTexSvxHatch* >(&rGeoTexSvx); |
870 | 0 | return (pCompare |
871 | 0 | && maOutputRange == pCompare->maOutputRange |
872 | 0 | && maTextureTransform == pCompare->maTextureTransform |
873 | 0 | && mfDistance == pCompare->mfDistance |
874 | 0 | && mfAngle == pCompare->mfAngle |
875 | 0 | && mnSteps == pCompare->mnSteps); |
876 | 0 | } |
877 | | |
878 | | void GeoTexSvxHatch::appendTransformations(std::vector< basegfx::B2DHomMatrix >& rMatrices) |
879 | 0 | { |
880 | 0 | if(mbDefinitionRangeEqualsOutputRange) |
881 | 0 | { |
882 | | // simple hatch where the definition area equals the output area |
883 | 0 | for(sal_uInt32 a(1); a < mnSteps; a++) |
884 | 0 | { |
885 | | // create matrix |
886 | 0 | const double fOffset(mfDistance * static_cast<double>(a)); |
887 | 0 | basegfx::B2DHomMatrix aNew; |
888 | 0 | aNew.set(1, 2, fOffset); |
889 | 0 | rMatrices.push_back(maTextureTransform * aNew); |
890 | 0 | } |
891 | 0 | } |
892 | 0 | else |
893 | 0 | { |
894 | | // output area is different from definition area, back-transform to get |
895 | | // the output area in unit coordinates and fill this with hatch lines |
896 | | // using the settings derived from the definition area |
897 | 0 | basegfx::B2DRange aBackUnitRange(maOutputRange); |
898 | |
|
899 | 0 | aBackUnitRange.transform(getBackTextureTransform()); |
900 | | |
901 | | // calculate vertical start value and a security maximum integer value to avoid death loops |
902 | 0 | double fStart(basegfx::snapToNearestMultiple(aBackUnitRange.getMinY(), mfDistance)); |
903 | 0 | const sal_uInt32 nNeededIntegerSteps(basegfx::fround((aBackUnitRange.getHeight() / mfDistance) + 0.5)); |
904 | 0 | sal_uInt32 nMaxIntegerSteps(std::min(nNeededIntegerSteps, sal_uInt32(10000))); |
905 | |
|
906 | 0 | while(fStart < aBackUnitRange.getMaxY() && nMaxIntegerSteps) |
907 | 0 | { |
908 | | // create new transform for |
909 | 0 | basegfx::B2DHomMatrix aNew; |
910 | | |
911 | | // adapt x scale and position |
912 | | //aNew.scale(aBackUnitRange.getWidth(), 1.0); |
913 | | //aNew.translate(aBackUnitRange.getMinX(), 0.0); |
914 | 0 | aNew.set(0, 0, aBackUnitRange.getWidth()); |
915 | 0 | aNew.set(0, 2, aBackUnitRange.getMinX()); |
916 | | |
917 | | // adapt y position to current step |
918 | 0 | aNew.set(1, 2, fStart); |
919 | | //aNew.translate(0.0, fStart); |
920 | | |
921 | | // add new transformation |
922 | 0 | rMatrices.push_back(maTextureTransform * aNew); |
923 | | |
924 | | // next step |
925 | 0 | fStart += mfDistance; |
926 | 0 | nMaxIntegerSteps--; |
927 | 0 | } |
928 | 0 | } |
929 | 0 | } |
930 | | |
931 | | double GeoTexSvxHatch::getDistanceToHatch(const basegfx::B2DPoint& rUV) const |
932 | 0 | { |
933 | | // the below is an inlined and optimised version of |
934 | | // const basegfx::B2DPoint aCoor(getBackTextureTransform() * rUV); |
935 | | // return fmod(aCoor.getY(), mfDistance); |
936 | |
|
937 | 0 | const basegfx::B2DHomMatrix& rMat = getBackTextureTransform(); |
938 | 0 | double fX = rUV.getX(); |
939 | 0 | double fY = rUV.getY(); |
940 | |
|
941 | 0 | double fTempY( |
942 | 0 | rMat.get(1, 0) * fX + |
943 | 0 | rMat.get(1, 1) * fY + |
944 | 0 | rMat.get(1, 2)); |
945 | |
|
946 | 0 | return fmod(fTempY, mfDistance); |
947 | 0 | } |
948 | | |
949 | | const basegfx::B2DHomMatrix& GeoTexSvxHatch::getBackTextureTransform() const |
950 | 0 | { |
951 | 0 | if(maBackTextureTransform.isIdentity()) |
952 | 0 | { |
953 | 0 | const_cast< GeoTexSvxHatch* >(this)->maBackTextureTransform = maTextureTransform; |
954 | 0 | const_cast< GeoTexSvxHatch* >(this)->maBackTextureTransform.invert(); |
955 | 0 | } |
956 | |
|
957 | 0 | return maBackTextureTransform; |
958 | 0 | } |
959 | | |
960 | | |
961 | | GeoTexSvxTiled::GeoTexSvxTiled( |
962 | | const basegfx::B2DRange& rRange, |
963 | | double fOffsetX, |
964 | | double fOffsetY) |
965 | 0 | : maRange(rRange), |
966 | 0 | mfOffsetX(std::clamp(fOffsetX, 0.0, 1.0)), |
967 | 0 | mfOffsetY(std::clamp(fOffsetY, 0.0, 1.0)) |
968 | 0 | { |
969 | 0 | if(!basegfx::fTools::equalZero(mfOffsetX)) |
970 | 0 | { |
971 | 0 | mfOffsetY = 0.0; |
972 | 0 | } |
973 | 0 | } |
974 | | |
975 | | GeoTexSvxTiled::~GeoTexSvxTiled() |
976 | | { |
977 | | } |
978 | | |
979 | | bool GeoTexSvxTiled::operator==(const GeoTexSvx& rGeoTexSvx) const |
980 | 0 | { |
981 | 0 | const GeoTexSvxTiled* pCompare = dynamic_cast< const GeoTexSvxTiled* >(&rGeoTexSvx); |
982 | |
|
983 | 0 | return (pCompare |
984 | 0 | && maRange == pCompare->maRange |
985 | 0 | && mfOffsetX == pCompare->mfOffsetX |
986 | 0 | && mfOffsetY == pCompare->mfOffsetY); |
987 | 0 | } |
988 | | |
989 | | sal_uInt32 GeoTexSvxTiled::getNumberOfTiles() const |
990 | 0 | { |
991 | 0 | sal_Int32 nTiles = 0; |
992 | 0 | iterateTiles([&](double, double) { ++nTiles; }); |
993 | 0 | return nTiles; |
994 | 0 | } |
995 | | |
996 | | void GeoTexSvxTiled::appendTransformations(std::vector< basegfx::B2DHomMatrix >& rMatrices) const |
997 | 0 | { |
998 | 0 | const double fWidth(maRange.getWidth()); |
999 | 0 | const double fHeight(maRange.getHeight()); |
1000 | 0 | iterateTiles([&](double fPosX, double fPosY) { |
1001 | 0 | rMatrices.push_back(basegfx::utils::createScaleTranslateB2DHomMatrix( |
1002 | 0 | fWidth, |
1003 | 0 | fHeight, |
1004 | 0 | fPosX, |
1005 | 0 | fPosY)); |
1006 | 0 | }); |
1007 | 0 | } |
1008 | | |
1009 | | void GeoTexSvxTiled::iterateTiles(std::function<void(double fPosX, double fPosY)> aFunc) const |
1010 | 0 | { |
1011 | 0 | const double fWidth(maRange.getWidth()); |
1012 | |
|
1013 | 0 | if(basegfx::fTools::equalZero(fWidth)) |
1014 | 0 | return; |
1015 | | |
1016 | 0 | const double fHeight(maRange.getHeight()); |
1017 | |
|
1018 | 0 | if(basegfx::fTools::equalZero(fHeight)) |
1019 | 0 | return; |
1020 | | |
1021 | 0 | double fStartX(maRange.getMinX()); |
1022 | 0 | double fStartY(maRange.getMinY()); |
1023 | 0 | sal_Int32 nPosX(0); |
1024 | 0 | sal_Int32 nPosY(0); |
1025 | |
|
1026 | 0 | if(fStartX > 0.0) |
1027 | 0 | { |
1028 | 0 | const sal_Int32 nDiff(static_cast<sal_Int32>(floor(fStartX / fWidth)) + 1); |
1029 | |
|
1030 | 0 | nPosX -= nDiff; |
1031 | 0 | fStartX -= nDiff * fWidth; |
1032 | 0 | } |
1033 | |
|
1034 | 0 | if((fStartX + fWidth) < 0.0) |
1035 | 0 | { |
1036 | 0 | const sal_Int32 nDiff(static_cast<sal_Int32>(floor(-fStartX / fWidth))); |
1037 | |
|
1038 | 0 | nPosX += nDiff; |
1039 | 0 | fStartX += nDiff * fWidth; |
1040 | 0 | } |
1041 | |
|
1042 | 0 | if(fStartY > 0.0) |
1043 | 0 | { |
1044 | 0 | const sal_Int32 nDiff(static_cast<sal_Int32>(floor(fStartY / fHeight)) + 1); |
1045 | |
|
1046 | 0 | nPosY -= nDiff; |
1047 | 0 | fStartY -= nDiff * fHeight; |
1048 | 0 | } |
1049 | |
|
1050 | 0 | if((fStartY + fHeight) < 0.0) |
1051 | 0 | { |
1052 | 0 | const sal_Int32 nDiff(static_cast<sal_Int32>(floor(-fStartY / fHeight))); |
1053 | |
|
1054 | 0 | nPosY += nDiff; |
1055 | 0 | fStartY += nDiff * fHeight; |
1056 | 0 | } |
1057 | |
|
1058 | 0 | if(!basegfx::fTools::equalZero(mfOffsetY)) |
1059 | 0 | { |
1060 | 0 | for(double fPosX(fStartX); basegfx::fTools::less(fPosX, 1.0); fPosX += fWidth, nPosX++) |
1061 | 0 | { |
1062 | 0 | for(double fPosY((nPosX % 2) ? fStartY - fHeight + (mfOffsetY * fHeight) : fStartY); |
1063 | 0 | basegfx::fTools::less(fPosY, 1.0); fPosY += fHeight) |
1064 | 0 | aFunc(fPosX, fPosY); |
1065 | 0 | } |
1066 | 0 | } |
1067 | 0 | else |
1068 | 0 | { |
1069 | 0 | for(double fPosY(fStartY); basegfx::fTools::less(fPosY, 1.0); fPosY += fHeight, nPosY++) |
1070 | 0 | { |
1071 | 0 | for(double fPosX((nPosY % 2) ? fStartX - fWidth + (mfOffsetX * fWidth) : fStartX); |
1072 | 0 | basegfx::fTools::less(fPosX, 1.0); fPosX += fWidth) |
1073 | 0 | aFunc(fPosX, fPosY); |
1074 | 0 | } |
1075 | 0 | } |
1076 | |
|
1077 | 0 | } |
1078 | | |
1079 | | } // end of namespace |
1080 | | |
1081 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |