7 VLine():mX1(0),mY1(0),mX2(0),mY2(0){}
8 VLine(float x1, float y1, float x2, float y2):mX1(x1),mY1(y1),mX2(x2),mY2(y2){}
9 VLine(const VPointF &p1, const VPointF &p2):mX1(p1.x()),mY1(p1.y()),mX2(p2.x()),mY2(p2.y()){}
11 void splitAtLength(float length, VLine &left, VLine &right) const;
12 VPointF p1() const {return VPointF(mX1, mY1);}
13 VPointF p2() const {return VPointF(mX2, mY2);}
21 // approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
22 // With alpha = 1, beta = 3/8, giving results with the largest error less
23 // than 7% compared to the exact value.
31 return (x > y ? x + 0.375 * y : y + 0.375 * x);
35 VLine::splitAtLength(float lengthAt, VLine &left, VLine &right) const
38 double dx = ((mX2 - mX1)/len) *lengthAt;
39 double dy = ((mY2 - mY1)/len) *lengthAt;
43 left.mX2 = left.mX1 + dx;
44 left.mY2 = left.mY1 + dy;
52 VDasher::VDasher(const float *dashArray, int size)
55 vCritical<<"invalid dashArray format";
57 mDashArray = reinterpret_cast<const VDasher::Dash *>(dashArray);
59 mDashOffset = dashArray[size-1];
60 mCurrentDashIndex = 0;
61 mCurrentDashLength = 0;
62 mIsCurrentOperationGap = false;
65 void VDasher::moveTo(const VPointF &p)
67 mIsCurrentOperationGap = false;
71 if (!floatCmp(mDashOffset, 0.0)) {
72 float totalLength = 0.0;
73 for (int i = 0; i < mArraySize ; i++) {
74 totalLength = mDashArray[i].length + mDashArray[i].gap;
76 float normalizeLen = fmod(mDashOffset, totalLength);
77 if (normalizeLen < 0.0 ) {
78 normalizeLen = totalLength + normalizeLen;
80 // now the length is less than total length and +ve
81 // findout the current dash index , dashlength and gap.
82 for (int i = 0; i < mArraySize; i++) {
83 if (normalizeLen < mDashArray[i].length) {
84 mCurrentDashIndex = i;
85 mCurrentDashLength = mDashArray[i].length - normalizeLen;
86 mIsCurrentOperationGap = false;
89 normalizeLen -= mDashArray[i].length;
90 if (normalizeLen < mDashArray[i].gap) {
91 mCurrentDashIndex = i;
92 mCurrentDashLength = mDashArray[i].gap - normalizeLen;
93 mIsCurrentOperationGap = true;
96 normalizeLen -= mDashArray[i].gap;
99 mCurrentDashIndex = 0;
100 mCurrentDashLength = mDashArray[0].length;
104 void VDasher::lineTo(const VPointF &p)
107 VLine line(mCurPt, p);
108 float length = line.length();
109 if (length < mCurrentDashLength) {
110 mCurrentDashLength -= length;
111 if (!mIsCurrentOperationGap) {
112 mDashedPath.moveTo(mCurPt);
113 mDashedPath.lineTo(p);
116 while (length > mCurrentDashLength) {
117 length -= mCurrentDashLength;
118 line.splitAtLength(mCurrentDashLength, left, right);
119 if (!mIsCurrentOperationGap) {
120 mDashedPath.moveTo(left.p1());
121 mDashedPath.lineTo(left.p2());
122 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
124 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize ;
125 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
127 mIsCurrentOperationGap = !mIsCurrentOperationGap;
132 mCurrentDashLength -= length;
133 if (!mIsCurrentOperationGap) {
134 mDashedPath.moveTo(line.p1());
135 mDashedPath.lineTo(line.p2());
137 if (mCurrentDashLength < 1.0) {
139 if (!mIsCurrentOperationGap) {
140 mIsCurrentOperationGap = true;
141 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
143 mIsCurrentOperationGap = false;
144 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize;
145 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
152 void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
156 VBezier b = VBezier::fromPoints(mCurPt, cp1, cp2, e);
158 if (bezLen < mCurrentDashLength) {
159 mCurrentDashLength -= bezLen;
160 if (!mIsCurrentOperationGap) {
161 mDashedPath.moveTo(mCurPt);
162 mDashedPath.cubicTo(cp1, cp2, e);
165 while (bezLen > mCurrentDashLength) {
166 bezLen -= mCurrentDashLength;
167 b.splitAtLength(mCurrentDashLength, &left, &right);
168 if (!mIsCurrentOperationGap) {
169 mDashedPath.moveTo(left.pt1());
170 mDashedPath.cubicTo(left.pt2(), left.pt3(), left.pt4());;
171 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
173 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize ;
174 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
176 mIsCurrentOperationGap = !mIsCurrentOperationGap;
181 mCurrentDashLength -= bezLen;
182 if (!mIsCurrentOperationGap) {
183 mDashedPath.moveTo(b.pt1());
184 mDashedPath.cubicTo(b.pt2(), b.pt3(), b.pt4());
186 if (mCurrentDashLength < 1.0) {
188 if (!mIsCurrentOperationGap)
190 mIsCurrentOperationGap = true;
191 mCurrentDashLength = mDashArray[mCurrentDashIndex].gap;
195 mIsCurrentOperationGap = false;
196 mCurrentDashIndex = (mCurrentDashIndex +1) % mArraySize;
197 mCurrentDashLength = mDashArray[mCurrentDashIndex].length;
205 VPath VDasher::dashed(const VPath &path)
207 if (path.isEmpty()) return VPath();
209 mDashedPath = VPath();
210 const std::vector<VPath::Element> &elms = path.elements();
211 const std::vector<VPointF> &pts = path.points();
212 const VPointF *ptPtr = pts.data();
214 for (auto i : elms) {
216 case VPath::Element::MoveTo: {
220 case VPath::Element::LineTo: {
224 case VPath::Element::CubicTo: {
225 cubicTo(*ptPtr, *(ptPtr + 1), *(ptPtr + 2));
229 case VPath::Element::Close: {
230 // The point is already joined to start point in VPath
231 // no need to do anything here.