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 GiGraphics::drawPathWithArrayHead(const GiContext& ctx, MgPath& path, int startArray, int endArray) { float px = calcPenWidth(ctx.getLineWidth(), ctx.isAutoScale()); float scale = 0.5f * xf().getWorldToDisplayX() * (1 + mgMax(0.f, (px - 4.f) / 5)); if (startArray > 0 && startArray <= GiContext::kArrowOpenedCircle) { drawArrayHead(ctx, path, startArray, px, scale); } if (endArray > 0 && endArray <= GiContext::kArrowOpenedCircle) { path.reverse(); drawArrayHead(ctx, path, endArray, px, scale); path.reverse(); } return drawPath_(&ctx, path, false, Matrix2d::kIdentity()); }
bool GiGraphics::drawPath(const GiContext* ctx, const MgPath& path, bool fill, bool modelUnit) { if (ctx && ctx->hasArrayHead() && path.getSubPathCount() == 1 && !path.isClosed()) { MgPath pathw(path); GiContext ctx2(*ctx); pathw.transform(S2D(xf(), modelUnit)); ctx2.setNoFillColor(); ctx2.setStartArrayHead(0); ctx2.setEndArrayHead(0); return drawPathWithArrayHead(ctx2, pathw, ctx->getStartArrayHead(), ctx->getEndArrayHead()); } return drawPath_(ctx, path, fill, S2D(xf(), modelUnit)); }
void GiGraphics::drawArrayHead(const GiContext& ctx, MgPath& path, int type, float px, float scale) { float xoffset = _arrayHeads[type - 1].xoffset * scale; Point2d startpt(path.getStartPoint()); path.trimStart(startpt, xoffset + px / 2); Matrix2d mat(Matrix2d::translation(startpt.asVector())); Vector2d vec(mgIsZero(xoffset) ? path.getStartTangent() : path.getStartPoint() - startpt); mat *= Matrix2d::rotation(vec.angle2(), startpt); mat *= Matrix2d::scaling(scale, startpt); MgPath headPath(_arrayHeads[type - 1].types); headPath.transform(mat); GiContext ctxhead(ctx); if (_arrayHeads[type - 1].fill) { ctxhead.setFillColor(ctxhead.getLineColor()); ctxhead.setNullLine(); } drawPath_(&ctxhead, headPath, ctxhead.hasFillColor(), Matrix2d::kIdentity()); }
void MgArc::_output(MgPath& path) const { float r = getRadius(); float sweepAngle = getSweepAngle(); Point2d points[16]; if (r < _MGZERO || fabsf(sweepAngle) < _MGZERO) return; int count = mgcurv::arcToBezier(points, getCenter(), r, r, getStartAngle(), sweepAngle); if (_subtype > 0) { path.moveTo(getCenter()); path.lineTo(points[0]); path.beziersTo(count - 1, points + 1); path.closeFigure(); } else { path.moveTo(points[0]); path.beziersTo(count - 1, points + 1); } }
void MgEllipse::_output(MgPath& path) const { path.moveTo(_bzpts[0]); path.beziersTo(12, _bzpts + 1); path.closeFigure(); }
void MgBaseRect::_output(MgPath& path) const { path.moveTo(_points[0]); path.linesTo(3, _points + 1); path.closeFigure(); }
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; }