xref: /trunk/main/basegfx/source/curve/b2dbeziertools.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basegfx.hxx"
30 #include <basegfx/curve/b2dbeziertools.hxx>
31 #include <basegfx/curve/b2dcubicbezier.hxx>
32 #include <algorithm>
33 
34 //////////////////////////////////////////////////////////////////////////////
35 
36 namespace basegfx
37 {
38     B2DCubicBezierHelper::B2DCubicBezierHelper(const B2DCubicBezier& rBase, sal_uInt32 nDivisions)
39     :   maLengthArray(),
40         mnEdgeCount(0)
41     {
42         const bool bIsBezier(rBase.isBezier());
43 
44         if(bIsBezier)
45         {
46             // check nDivisions; at least one is needed, but also prevent too big values
47             if(nDivisions < 1)
48             {
49                 nDivisions = 1;
50             }
51             else if(nDivisions > 1000)
52             {
53                 nDivisions = 1000;
54             }
55 
56             // set nEdgeCount
57             mnEdgeCount = nDivisions + 1;
58 
59             // fill in maLengthArray
60             maLengthArray.clear();
61             maLengthArray.reserve(mnEdgeCount);
62             B2DPoint aCurrent(rBase.getStartPoint());
63             double fLength(0.0);
64 
65             for(sal_uInt32 a(1);;)
66             {
67                 const B2DPoint aNext(rBase.interpolatePoint((double)a / (double)mnEdgeCount));
68                 const B2DVector aEdge(aNext - aCurrent);
69 
70                 fLength += aEdge.getLength();
71                 maLengthArray.push_back(fLength);
72 
73                 if(++a < mnEdgeCount)
74                 {
75                     aCurrent = aNext;
76                 }
77                 else
78                 {
79                     const B2DPoint aLastNext(rBase.getEndPoint());
80                     const B2DVector aLastEdge(aLastNext - aNext);
81 
82                     fLength += aLastEdge.getLength();
83                     maLengthArray.push_back(fLength);
84                     break;
85                 }
86             }
87         }
88         else
89         {
90             maLengthArray.clear();
91             maLengthArray.push_back(rBase.getEdgeLength());
92             mnEdgeCount = 1;
93         }
94     }
95 
96     double B2DCubicBezierHelper::distanceToRelative(double fDistance) const
97     {
98         if(fDistance <= 0.0)
99         {
100             return 0.0;
101         }
102 
103         const double fLength(getLength());
104 
105         if(fTools::moreOrEqual(fDistance, fLength))
106         {
107             return 1.0;
108         }
109 
110         // fDistance is in ]0.0 .. fLength[
111 
112         if(1 == mnEdgeCount)
113         {
114             // not a bezier, linear edge
115             return fDistance / fLength;
116         }
117 
118         // it is a bezier
119         ::std::vector< double >::const_iterator aIter = ::std::lower_bound(maLengthArray.begin(), maLengthArray.end(), fDistance);
120         const sal_uInt32 nIndex(aIter - maLengthArray.begin());
121         const double fHighBound(maLengthArray[nIndex]);
122         const double fLowBound(nIndex ?  maLengthArray[nIndex - 1] : 0.0);
123         const double fLinearInterpolatedLength((fDistance - fLowBound) / (fHighBound - fLowBound));
124 
125         return (static_cast< double >(nIndex) + fLinearInterpolatedLength) / static_cast< double >(mnEdgeCount);
126     }
127 
128     double B2DCubicBezierHelper::relativeToDistance(double fRelative) const
129     {
130         if(fRelative <= 0.0)
131         {
132             return 0.0;
133         }
134 
135         const double fLength(getLength());
136 
137         if(fTools::moreOrEqual(fRelative, 1.0))
138         {
139             return fLength;
140         }
141 
142         // fRelative is in ]0.0 .. 1.0[
143 
144         if(1 == mnEdgeCount)
145         {
146             // not a bezier, linear edge
147             return fRelative * fLength;
148         }
149 
150         // fRelative is in ]0.0 .. 1.0[
151         const double fIndex(fRelative * static_cast< double >(mnEdgeCount));
152         double fIntIndex;
153         const double fFractIndex(modf(fIndex, &fIntIndex));
154         const sal_uInt32 nIntIndex(static_cast< sal_uInt32 >(fIntIndex));
155         const double fStartDistance(nIntIndex ? maLengthArray[nIntIndex - 1] : 0.0);
156 
157         return fStartDistance + ((maLengthArray[nIntIndex] - fStartDistance) * fFractIndex);
158     }
159 } // end of namespace basegfx
160 
161 //////////////////////////////////////////////////////////////////////////////
162 
163 // eof
164