MgPath& MgPath::reverse() { if (getSubPathCount() > 1) { MgPath subpath; std::list<MgPath> paths; for (size_t i = 0; i < m_data->types.size(); i++) { if (m_data->types[i] == kMgMoveTo && subpath.getCount() > 0) { paths.push_back(subpath); subpath.clear(); } subpath.m_data->types.push_back(m_data->types[i]); subpath.m_data->points.push_back(m_data->points[i]); } if (subpath.getCount() > 0) { paths.push_back(subpath); } clear(); for (std::list<MgPath>::reverse_iterator it = paths.rbegin(); it != paths.rend(); ++it) { append(it->reverse()); } } else { for (int i = 0, j = getCount() - 1; i < j; i++, j--) { if (i > 0) { mgSwap(m_data->types[i], m_data->types[j]); } mgSwap(m_data->points[i], m_data->points[j]); } } return *this; }
bool GiGraphics::drawPath_(const GiContext* ctx, const MgPath& path, bool fill, const Matrix2d& matD) { int n = path.getCount(); if (n == 0 || isStopping()) return false; const Point2d* pts = path.getPoints(); const char* types = path.getTypes(); Point2d ends, cp1, cp2; bool matsame = matD.isIdentity(); rawBeginPath(); for (int i = 0; i < n; i++) { switch (types[i] & ~kMgCloseFigure) { case kMgMoveTo: ends = matsame ? pts[i] : (pts[i] * matD); rawMoveTo(ends.x, ends.y); break; case kMgLineTo: ends = matsame ? pts[i] : (pts[i] * matD); rawLineTo(ends.x, ends.y); break; case kMgBezierTo: if (i + 2 >= n) return false; cp1 = matsame ? pts[i] : (pts[i] * matD); cp2 = matsame ? pts[i+1] : (pts[i+1] * matD); ends = matsame ? pts[i+2] : (pts[i+2] * matD); rawBezierTo(cp1.x, cp1.y, cp2.x, cp2.y, ends.x, ends.y); i += 2; break; case kMgQuadTo: if (i + 1 >= n) return false; cp1 = matsame ? pts[i] : (pts[i] * matD); ends = matsame ? pts[i+1] : (pts[i+1] * matD); rawQuadTo(cp1.x, cp1.y, ends.x, ends.y); i++; break; default: return false; } if (types[i] & kMgCloseFigure) rawClosePath(); } return rawEndPath(ctx, fill); }
bool MgPath::crossWithPath(const MgPath& p, const Box2d& box, Point2d& ptCross) const { MgPathCrossCallback cc(box, ptCross); if (isLine() && p.isLine()) { return (mglnrel::cross2Line(getPoint(0), getPoint(1), p.getPoint(0), p.getPoint(1), ptCross) && box.contains(ptCross)); } if (isLines() && p.isLines()) { for (int m = getCount() - (isClosed() ? 0 : 1), i = 0; i < m; i++) { Point2d a(getPoint(i)), b(getPoint(i + 1)); for (int n = p.getCount() - (p.isClosed() ? 0 : 1), j = 0; j < n; j++) { Point2d c(p.getPoint(j)), d(p.getPoint(j + 1)); if (mglnrel::cross2Line(a, b, c, d, cc.tmpcross) && box.contains(cc.tmpcross)) { float dist = cc.tmpcross.distanceTo(box.center()); if (cc.mindist > dist) { cc.mindist = dist; ptCross = cc.tmpcross; } } } } } else if (isLine() && p.getSubPathCount() == 1) { cc.a = getPoint(0); cc.b = getPoint(1); p.scanSegments(cc); } else if (p.isLine() && getSubPathCount() == 1) { cc.a = p.getPoint(0); cc.b = p.getPoint(1); scanSegments(cc); } return cc.mindist < box.width(); }
bool MgPath::scanSegments(MgSegmentCallback& c) const { bool ret = true; if (getSubPathCount() > 1) { MgPath subpath; std::list<MgPath> paths; for (size_t i = 0; i < m_data->types.size(); i++) { if (m_data->types[i] == kMgMoveTo && subpath.getCount() > 0) { paths.push_back(subpath); subpath.clear(); } subpath.m_data->types.push_back(m_data->types[i]); subpath.m_data->points.push_back(m_data->points[i]); } if (subpath.getCount() > 0) { paths.push_back(subpath); } for (std::list<MgPath>::reverse_iterator it = paths.rbegin(); ret && it != paths.rend(); ++it) { ret = it->scanSegments(c); } } else { Point2d pts[4]; int i, startIndex = 0, type = 0; for (i = 0; i < getCount() && ret; startIndex = ++i - 1) { type = m_data->types[i] & ~kMgCloseFigure; switch (type) { case kMgMoveTo: pts[0] = m_data->points[i]; c.beginSubPath(); break; case kMgLineTo: pts[1] = m_data->points[i]; ret = c.processLine(startIndex, i, pts[0], pts[1]); pts[0] = pts[1]; break; case kMgBezierTo: if (i + 2 >= getCount()) return false; pts[1] = m_data->points[i++]; pts[2] = m_data->points[i++]; pts[3] = m_data->points[i]; ret = c.processBezier(startIndex, i, pts); pts[0] = pts[3]; break; case kMgQuadTo: if (i + 1 >= getCount()) return false; pts[2] = m_data->points[i++]; pts[3] = m_data->points[i]; pts[1] = (pts[0] + pts[2] * 2) / 3; pts[2] = (pts[3] + pts[2] * 2) / 3; ret = c.processBezier(startIndex, i, pts); pts[0] = pts[3]; break; default: return false; } } if (isClosed()) { i = 0; switch (type) { case kMgLineTo: ret = c.processLine(startIndex, i, pts[0], m_data->points[0]); break; case kMgBezierTo: pts[1] = 2 * pts[0] + (- m_data->points[getCount() - 2]); pts[3] = m_data->points[0]; pts[2] = 2 * pts[3] + (- m_data->points[1]); ret = c.processBezier(startIndex, i, pts); break; case kMgQuadTo: pts[3] = m_data->points[0]; pts[2] = 2 * pts[3] + (- m_data->points[1]); pts[1] = (pts[0] + pts[2] * 2) / 3; pts[2] = (pts[3] + pts[2] * 2) / 3; ret = c.processBezier(startIndex, i, pts); break; default: break; } } c.endSubPath(isClosed()); } return ret; }