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;
77 if (!vCompare(mDashOffset, 0.0f)) {
78 float totalLength = 0.0;
79 for (int i = 0; i < mArraySize; i++) {
80 totalLength = mDashArray[i].length + mDashArray[i].gap;
82 float normalizeLen = fmod(mDashOffset, totalLength);
83 if (normalizeLen < 0.0) {
84 normalizeLen = totalLength + normalizeLen;
86 // now the length is less than total length and +ve
87 // findout the current dash index , dashlength and gap.
88 for (int i = 0; i < mArraySize; i++) {
89 if (normalizeLen < mDashArray[i].length) {
91 mCurrentLength = mDashArray[i].length - normalizeLen;
95 normalizeLen -= mDashArray[i].length;
96 if (normalizeLen < mDashArray[i].gap) {
98 mCurrentLength = mDashArray[i].gap - normalizeLen;
102 normalizeLen -= mDashArray[i].gap;
105 mCurrentLength = mDashArray[mIndex].length;
109 void VDasher::addLine(const VPointF &p)
111 if (mDiscard) return;
113 if (mStartNewSegment) {
114 mResult.moveTo(mCurPt);
115 mStartNewSegment = false;
120 void VDasher::updateActiveSegment()
122 mStartNewSegment = true;
126 mIndex = (mIndex + 1) % mArraySize;
127 mCurrentLength = mDashArray[mIndex].length;
130 mCurrentLength = mDashArray[mIndex].gap;
134 void VDasher::lineTo(const VPointF &p)
137 VLine line(mCurPt, p);
138 float length = line.length();
140 if (length <= mCurrentLength) {
141 mCurrentLength -= length;
144 while (length > mCurrentLength) {
145 length -= mCurrentLength;
146 line.splitAtLength(mCurrentLength, left, right);
149 updateActiveSegment();
156 mCurrentLength -= length;
161 if (mCurrentLength < 1.0) updateActiveSegment();
166 void VDasher::addCubic(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
168 if (mDiscard) return;
170 if (mStartNewSegment) {
171 mResult.moveTo(mCurPt);
172 mStartNewSegment = false;
174 mResult.cubicTo(cp1, cp2, e);
177 void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
181 VBezier b = VBezier::fromPoints(mCurPt, cp1, cp2, e);
184 if (bezLen <= mCurrentLength) {
185 mCurrentLength -= bezLen;
186 addCubic(cp1, cp2, e);
188 while (bezLen > mCurrentLength) {
189 bezLen -= mCurrentLength;
190 b.splitAtLength(mCurrentLength, &left, &right);
192 addCubic(left.pt2(), left.pt3(), left.pt4());
193 updateActiveSegment();
200 mCurrentLength -= bezLen;
201 addCubic(b.pt2(), b.pt3(), b.pt4());
205 if (mCurrentLength < 1.0) updateActiveSegment();
210 VPath VDasher::dashed(const VPath &path)
212 if (path.isEmpty()) return VPath();
216 const std::vector<VPath::Element> &elms = path.elements();
217 const std::vector<VPointF> & pts = path.points();
218 const VPointF * ptPtr = pts.data();
220 for (auto &i : elms) {
222 case VPath::Element::MoveTo: {
226 case VPath::Element::LineTo: {
230 case VPath::Element::CubicTo: {
231 cubicTo(*ptPtr, *(ptPtr + 1), *(ptPtr + 2));
235 case VPath::Element::Close: {
236 // The point is already joined to start point in VPath
237 // no need to do anything here.
244 return std::move(mResult);