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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_basegfx.hxx" 24 #include <basegfx/curve/b2dbeziertools.hxx> 25 #include <basegfx/curve/b2dcubicbezier.hxx> 26 #include <algorithm> 27 28 namespace basegfx 29 { 30 B2DCubicBezierHelper::B2DCubicBezierHelper(const B2DCubicBezier& rBase, sal_uInt32 nDivisions) 31 : maLengthArray(), 32 mnEdgeCount(0) 33 { 34 const bool bIsBezier(rBase.isBezier()); 35 36 if(bIsBezier) 37 { 38 // check nDivisions; at least one is needed, but also prevent too big values 39 if(nDivisions < 1) 40 { 41 nDivisions = 1; 42 } 43 else if(nDivisions > 1000) 44 { 45 nDivisions = 1000; 46 } 47 48 // set nEdgeCount 49 mnEdgeCount = nDivisions + 1; 50 51 // fill in maLengthArray 52 maLengthArray.clear(); 53 maLengthArray.reserve(mnEdgeCount); 54 B2DPoint aCurrent(rBase.getStartPoint()); 55 double fLength(0.0); 56 57 for(sal_uInt32 a(1);;) 58 { 59 const B2DPoint aNext(rBase.interpolatePoint((double)a / (double)mnEdgeCount)); 60 const B2DVector aEdge(aNext - aCurrent); 61 62 fLength += aEdge.getLength(); 63 maLengthArray.push_back(fLength); 64 65 if(++a < mnEdgeCount) 66 { 67 aCurrent = aNext; 68 } 69 else 70 { 71 const B2DPoint aLastNext(rBase.getEndPoint()); 72 const B2DVector aLastEdge(aLastNext - aNext); 73 74 fLength += aLastEdge.getLength(); 75 maLengthArray.push_back(fLength); 76 break; 77 } 78 } 79 } 80 else 81 { 82 maLengthArray.clear(); 83 maLengthArray.push_back(rBase.getEdgeLength()); 84 mnEdgeCount = 1; 85 } 86 } 87 88 double B2DCubicBezierHelper::distanceToRelative(double fDistance) const 89 { 90 if(fDistance <= 0.0) 91 { 92 return 0.0; 93 } 94 95 const double fLength(getLength()); 96 97 if(fTools::moreOrEqual(fDistance, fLength)) 98 { 99 return 1.0; 100 } 101 102 // fDistance is in ]0.0 .. fLength[ 103 104 if(1 == mnEdgeCount) 105 { 106 // not a bezier, linear edge 107 return fDistance / fLength; 108 } 109 110 // it is a bezier 111 ::std::vector< double >::const_iterator aIter = ::std::lower_bound(maLengthArray.begin(), maLengthArray.end(), fDistance); 112 const sal_uInt32 nIndex(aIter - maLengthArray.begin()); 113 const double fHighBound(maLengthArray[nIndex]); 114 const double fLowBound(nIndex ? maLengthArray[nIndex - 1] : 0.0); 115 const double fLinearInterpolatedLength((fDistance - fLowBound) / (fHighBound - fLowBound)); 116 117 return (static_cast< double >(nIndex) + fLinearInterpolatedLength) / static_cast< double >(mnEdgeCount); 118 } 119 120 double B2DCubicBezierHelper::relativeToDistance(double fRelative) const 121 { 122 if(fRelative <= 0.0) 123 { 124 return 0.0; 125 } 126 127 const double fLength(getLength()); 128 129 if(fTools::moreOrEqual(fRelative, 1.0)) 130 { 131 return fLength; 132 } 133 134 // fRelative is in ]0.0 .. 1.0[ 135 136 if(1 == mnEdgeCount) 137 { 138 // not a bezier, linear edge 139 return fRelative * fLength; 140 } 141 142 // fRelative is in ]0.0 .. 1.0[ 143 const double fIndex(fRelative * static_cast< double >(mnEdgeCount)); 144 double fIntIndex; 145 const double fFractIndex(modf(fIndex, &fIntIndex)); 146 const sal_uInt32 nIntIndex(static_cast< sal_uInt32 >(fIntIndex)); 147 const double fStartDistance(nIntIndex ? maLengthArray[nIntIndex - 1] : 0.0); 148 149 return fStartDistance + ((maLengthArray[nIntIndex] - fStartDistance) * fFractIndex); 150 } 151 } // end of namespace basegfx 152 153 /* vim: set noet sw=4 ts=4: */ 154