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