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