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