xref: /AOO41X/main/basegfx/source/curve/b2dbeziertools.cxx (revision 09dbbe930366fe6f99ae3b8ae1cf8690b638dbda)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 #include <basegfx/curve/b2dbeziertools.hxx>
27 #include <basegfx/curve/b2dcubicbezier.hxx>
28 #include <algorithm>
29 
30 //////////////////////////////////////////////////////////////////////////////
31 
32 namespace basegfx
33 {
B2DCubicBezierHelper(const B2DCubicBezier & rBase,sal_uInt32 nDivisions)34     B2DCubicBezierHelper::B2DCubicBezierHelper(const B2DCubicBezier& rBase, sal_uInt32 nDivisions)
35     :   maLengthArray(),
36         mnEdgeCount(0)
37     {
38         const bool bIsBezier(rBase.isBezier());
39 
40         if(bIsBezier)
41         {
42             // check nDivisions; at least one is needed, but also prevent too big values
43             if(nDivisions < 1)
44             {
45                 nDivisions = 1;
46             }
47             else if(nDivisions > 1000)
48             {
49                 nDivisions = 1000;
50             }
51 
52             // set nEdgeCount
53             mnEdgeCount = nDivisions + 1;
54 
55             // fill in maLengthArray
56             maLengthArray.clear();
57             maLengthArray.reserve(mnEdgeCount);
58             B2DPoint aCurrent(rBase.getStartPoint());
59             double fLength(0.0);
60 
61             for(sal_uInt32 a(1);;)
62             {
63                 const B2DPoint aNext(rBase.interpolatePoint((double)a / (double)mnEdgeCount));
64                 const B2DVector aEdge(aNext - aCurrent);
65 
66                 fLength += aEdge.getLength();
67                 maLengthArray.push_back(fLength);
68 
69                 if(++a < mnEdgeCount)
70                 {
71                     aCurrent = aNext;
72                 }
73                 else
74                 {
75                     const B2DPoint aLastNext(rBase.getEndPoint());
76                     const B2DVector aLastEdge(aLastNext - aNext);
77 
78                     fLength += aLastEdge.getLength();
79                     maLengthArray.push_back(fLength);
80                     break;
81                 }
82             }
83         }
84         else
85         {
86             maLengthArray.clear();
87             maLengthArray.push_back(rBase.getEdgeLength());
88             mnEdgeCount = 1;
89         }
90     }
91 
distanceToRelative(double fDistance) const92     double B2DCubicBezierHelper::distanceToRelative(double fDistance) const
93     {
94         if(fDistance <= 0.0)
95         {
96             return 0.0;
97         }
98 
99         const double fLength(getLength());
100 
101         if(fTools::moreOrEqual(fDistance, fLength))
102         {
103             return 1.0;
104         }
105 
106         // fDistance is in ]0.0 .. fLength[
107 
108         if(1 == mnEdgeCount)
109         {
110             // not a bezier, linear edge
111             return fDistance / fLength;
112         }
113 
114         // it is a bezier
115         ::std::vector< double >::const_iterator aIter = ::std::lower_bound(maLengthArray.begin(), maLengthArray.end(), fDistance);
116         const sal_uInt32 nIndex(aIter - maLengthArray.begin());
117         const double fHighBound(maLengthArray[nIndex]);
118         const double fLowBound(nIndex ?  maLengthArray[nIndex - 1] : 0.0);
119         const double fLinearInterpolatedLength((fDistance - fLowBound) / (fHighBound - fLowBound));
120 
121         return (static_cast< double >(nIndex) + fLinearInterpolatedLength) / static_cast< double >(mnEdgeCount);
122     }
123 
relativeToDistance(double fRelative) const124     double B2DCubicBezierHelper::relativeToDistance(double fRelative) const
125     {
126         if(fRelative <= 0.0)
127         {
128             return 0.0;
129         }
130 
131         const double fLength(getLength());
132 
133         if(fTools::moreOrEqual(fRelative, 1.0))
134         {
135             return fLength;
136         }
137 
138         // fRelative is in ]0.0 .. 1.0[
139 
140         if(1 == mnEdgeCount)
141         {
142             // not a bezier, linear edge
143             return fRelative * fLength;
144         }
145 
146         // fRelative is in ]0.0 .. 1.0[
147         const double fIndex(fRelative * static_cast< double >(mnEdgeCount));
148         double fIntIndex;
149         const double fFractIndex(modf(fIndex, &fIntIndex));
150         const sal_uInt32 nIntIndex(static_cast< sal_uInt32 >(fIntIndex));
151         const double fStartDistance(nIntIndex ? maLengthArray[nIntIndex - 1] : 0.0);
152 
153         return fStartDistance + ((maLengthArray[nIntIndex] - fStartDistance) * fFractIndex);
154     }
155 } // end of namespace basegfx
156 
157 //////////////////////////////////////////////////////////////////////////////
158 
159 // eof
160