8 VLine() : mX1(0), mY1(0), mX2(0), mY2(0) {}
9 VLine(float x1, float y1, float x2, float y2)
10 : mX1(x1), mY1(y1), mX2(x2), mY2(y2)
13 VLine(const VPointF &p1, const VPointF &p2)
14 : mX1(p1.x()), mY1(p1.y()), mX2(p2.x()), mY2(p2.y())
18 void splitAtLength(float length, VLine &left, VLine &right) const;
19 VPointF p1() const { return VPointF(mX1, mY1); }
20 VPointF p2() const { return VPointF(mX2, mY2); }
29 // approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
30 // With alpha = 1, beta = 3/8, giving results with the largest error less
31 // than 7% compared to the exact value.
32 float VLine::length() const
38 return (x > y ? x + 0.375 * y : y + 0.375 * x);
41 void VLine::splitAtLength(float lengthAt, VLine &left, VLine &right) const
44 double dx = ((mX2 - mX1) / len) * lengthAt;
45 double dy = ((mY2 - mY1) / len) * lengthAt;
49 left.mX2 = left.mX1 + dx;
50 left.mY2 = left.mY1 + dy;
58 VDasher::VDasher(const float *dashArray, int size)
60 if (!(size % 2)) vCritical << "invalid dashArray format";
62 mDashArray = reinterpret_cast<const VDasher::Dash *>(dashArray);
63 mArraySize = size / 2;
64 mDashOffset = dashArray[size - 1];
70 void VDasher::moveTo(const VPointF &p)
73 mStartNewSegment = true;
76 if (!vCompare(mDashOffset, 0.0f)) {
77 float totalLength = 0.0;
78 for (int i = 0; i < mArraySize; i++) {
79 totalLength = mDashArray[i].length + mDashArray[i].gap;
81 float normalizeLen = fmod(mDashOffset, totalLength);
82 if (normalizeLen < 0.0) {
83 normalizeLen = totalLength + normalizeLen;
85 // now the length is less than total length and +ve
86 // findout the current dash index , dashlength and gap.
87 for (int i = 0; i < mArraySize; i++) {
88 if (normalizeLen < mDashArray[i].length) {
90 mCurrentLength = mDashArray[i].length - normalizeLen;
94 normalizeLen -= mDashArray[i].length;
95 if (normalizeLen < mDashArray[i].gap) {
97 mCurrentLength = mDashArray[i].gap - normalizeLen;
101 normalizeLen -= mDashArray[i].gap;
104 mCurrentLength = mDashArray[mIndex].length;
108 void VDasher::addLine(const VPointF &p)
110 if (mDiscard) return;
112 if (mStartNewSegment) {
113 mResult.moveTo(mCurPt);
114 mStartNewSegment = false;
119 void VDasher::updateActiveSegment()
121 mStartNewSegment = true;
125 mIndex = (mIndex + 1) % mArraySize;
126 mCurrentLength = mDashArray[mIndex].length;
129 mCurrentLength = mDashArray[mIndex].gap;
133 void VDasher::lineTo(const VPointF &p)
136 VLine line(mCurPt, p);
137 float length = line.length();
139 if (length <= mCurrentLength) {
140 mCurrentLength -= length;
143 while (length > mCurrentLength) {
144 length -= mCurrentLength;
145 line.splitAtLength(mCurrentLength, left, right);
148 updateActiveSegment();
155 mCurrentLength -= length;
160 if (mCurrentLength < 1.0) updateActiveSegment();
165 void VDasher::addCubic(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
167 if (mDiscard) return;
169 if (mStartNewSegment) {
170 mResult.moveTo(mCurPt);
171 mStartNewSegment = false;
173 mResult.cubicTo(cp1, cp2, e);
176 void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
180 VBezier b = VBezier::fromPoints(mCurPt, cp1, cp2, e);
183 if (bezLen <= mCurrentLength) {
184 mCurrentLength -= bezLen;
185 addCubic(cp1, cp2, e);
187 while (bezLen > mCurrentLength) {
188 bezLen -= mCurrentLength;
189 b.splitAtLength(mCurrentLength, &left, &right);
191 addCubic(left.pt2(), left.pt3(), left.pt4());
192 updateActiveSegment();
199 mCurrentLength -= bezLen;
200 addCubic(b.pt2(), b.pt3(), b.pt4());
204 if (mCurrentLength < 1.0) updateActiveSegment();
209 VPath VDasher::dashed(const VPath &path)
211 if (path.isEmpty()) return VPath();
215 const std::vector<VPath::Element> &elms = path.elements();
216 const std::vector<VPointF> & pts = path.points();
217 const VPointF * ptPtr = pts.data();
219 for (auto &i : elms) {
221 case VPath::Element::MoveTo: {
225 case VPath::Element::LineTo: {
229 case VPath::Element::CubicTo: {
230 cubicTo(*ptPtr, *(ptPtr + 1), *(ptPtr + 2));
234 case VPath::Element::Close: {
235 // The point is already joined to start point in VPath
236 // no need to do anything here.
243 return std::move(mResult);