7 VDasher::VDasher(const float *dashArray, int size)
9 if (!(size % 2)) vCritical << "invalid dashArray format";
11 mDashArray = reinterpret_cast<const VDasher::Dash *>(dashArray);
12 mArraySize = size / 2;
13 mDashOffset = dashArray[size - 1];
19 void VDasher::moveTo(const VPointF &p)
22 mStartNewSegment = true;
26 if (!vCompare(mDashOffset, 0.0f)) {
27 float totalLength = 0.0;
28 for (int i = 0; i < mArraySize; i++) {
29 totalLength = mDashArray[i].length + mDashArray[i].gap;
31 float normalizeLen = fmod(mDashOffset, totalLength);
32 if (normalizeLen < 0.0) {
33 normalizeLen = totalLength + normalizeLen;
35 // now the length is less than total length and +ve
36 // findout the current dash index , dashlength and gap.
37 for (int i = 0; i < mArraySize; i++) {
38 if (normalizeLen < mDashArray[i].length) {
40 mCurrentLength = mDashArray[i].length - normalizeLen;
44 normalizeLen -= mDashArray[i].length;
45 if (normalizeLen < mDashArray[i].gap) {
47 mCurrentLength = mDashArray[i].gap - normalizeLen;
51 normalizeLen -= mDashArray[i].gap;
54 mCurrentLength = mDashArray[mIndex].length;
56 if (vIsZero(mCurrentLength)) updateActiveSegment();
59 void VDasher::addLine(const VPointF &p)
63 if (mStartNewSegment) {
64 mResult.moveTo(mCurPt);
65 mStartNewSegment = false;
70 void VDasher::updateActiveSegment()
72 mStartNewSegment = true;
76 mIndex = (mIndex + 1) % mArraySize;
77 mCurrentLength = mDashArray[mIndex].length;
80 mCurrentLength = mDashArray[mIndex].gap;
82 if (vIsZero(mCurrentLength)) updateActiveSegment();
85 void VDasher::lineTo(const VPointF &p)
88 VLine line(mCurPt, p);
89 float length = line.length();
91 if (length <= mCurrentLength) {
92 mCurrentLength -= length;
95 while (length > mCurrentLength) {
96 length -= mCurrentLength;
97 line.splitAtLength(mCurrentLength, left, right);
100 updateActiveSegment();
107 mCurrentLength -= length;
112 if (mCurrentLength < 1.0) updateActiveSegment();
117 void VDasher::addCubic(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
119 if (mDiscard) return;
121 if (mStartNewSegment) {
122 mResult.moveTo(mCurPt);
123 mStartNewSegment = false;
125 mResult.cubicTo(cp1, cp2, e);
128 void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e)
132 VBezier b = VBezier::fromPoints(mCurPt, cp1, cp2, e);
135 if (bezLen <= mCurrentLength) {
136 mCurrentLength -= bezLen;
137 addCubic(cp1, cp2, e);
139 while (bezLen > mCurrentLength) {
140 bezLen -= mCurrentLength;
141 b.splitAtLength(mCurrentLength, &left, &right);
143 addCubic(left.pt2(), left.pt3(), left.pt4());
144 updateActiveSegment();
151 mCurrentLength -= bezLen;
152 addCubic(b.pt2(), b.pt3(), b.pt4());
156 if (mCurrentLength < 1.0) updateActiveSegment();
161 VPath VDasher::dashed(const VPath &path)
163 if (path.empty()) return VPath();
167 const std::vector<VPath::Element> &elms = path.elements();
168 const std::vector<VPointF> & pts = path.points();
169 const VPointF * ptPtr = pts.data();
171 for (auto &i : elms) {
173 case VPath::Element::MoveTo: {
177 case VPath::Element::LineTo: {
181 case VPath::Element::CubicTo: {
182 cubicTo(*ptPtr, *(ptPtr + 1), *(ptPtr + 2));
186 case VPath::Element::Close: {
187 // The point is already joined to start point in VPath
188 // no need to do anything here.
195 return std::move(mResult);