bool mglnrel::cross2Line( const Point2d& a, const Point2d& b, const Point2d& c, const Point2d& d, Point2d& ptCross, const Tol& tolVec) { float u, v, denom, cosnum; if (mgMin(a.x,b.x) - mgMax(c.x,d.x) > _MGZERO || mgMin(c.x,d.x) - mgMax(a.x,b.x) > _MGZERO || mgMin(a.y,b.y) - mgMax(c.y,d.y) > _MGZERO || mgMin(c.y,d.y) - mgMax(a.y,b.y) > _MGZERO) return false; denom = (c.x-d.x)*(b.y-a.y)-(c.y-d.y)*(b.x-a.x); if (mgIsZero(denom)) return false; cosnum = (b.x-a.x)*(d.x - c.x) + (b.y-a.y)*(d.y-c.y); if (!mgIsZero(cosnum) && fabsf(denom / cosnum) < tolVec.equalVector()) return false; u = ((c.x-a.x)*(d.y-c.y)-(c.y-a.y)*(d.x-c.x)) / denom; if (u < _MGZERO || u > 1.f - _MGZERO) return false; v = ((c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x)) / denom; if (v < _MGZERO || v > 1.f - _MGZERO) return false; ptCross.x = (1 - u) * a.x + u * b.x; ptCross.y = (1 - u) * a.y + u * b.y; return true; }
bool mglnrel::cross2Beeline( const Point2d& a, const Point2d& b, const Point2d& c, const Point2d& d, Point2d& ptCross, float* pu, float* pv, const Tol& tolVec) { float u, v, denom, cosnum; denom = (c.x-d.x)*(b.y-a.y)-(c.y-d.y)*(b.x-a.x); if (mgIsZero(denom)) // 平行或重合 return false; cosnum = (b.x-a.x)*(d.x - c.x) + (b.y-a.y)*(d.y-c.y); if (!mgIsZero(cosnum) && fabsf(denom / cosnum) < tolVec.equalVector()) return false; u = ((c.x-a.x)*(d.y-c.y)-(c.y-a.y)*(d.x-c.x)) / denom; v = ((c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x)) / denom; if (pu) *pu = u; if (pv) *pv = v; ptCross.x = (1 - u) * a.x + u * b.x; ptCross.y = (1 - u) * a.y + u * b.y; return true; }
bool mgcurv::triEquations( int n, float *a, float *b, float *c, Vector2d *vs) { if (!a || !b || !c || !vs || n < 2) return false; float w; int i; w = b[0]; if (mgIsZero(w)) return false; w = 1 / w; vs[0].x = vs[0].x * w; vs[0].y = vs[0].y * w; for (i = 0; i <= n-2; i++) { b[i] = c[i] * w; w = b[i+1] - a[i] * b[i]; if (mgIsZero(w)) return false; w = 1 / w; vs[i+1].x = (vs[i+1].x - a[i] * vs[i].x) * w; vs[i+1].y = (vs[i+1].y - a[i] * vs[i].y) * w; } for (i = n-2; i >= 0; i--) { vs[i].x -= b[i] * vs[i+1].x; vs[i].y -= b[i] * vs[i+1].y; } return true; }
bool Matrix2d::isConformal(float& scaleX, float& scaleY, float& angle, bool& isMirror, Vector2d& reflex) const { Vector2d e0 (m11, m12); Vector2d e1 (m21, m22); if (!e0.isPerpendicularTo(e1)) return false; scaleX = e0.length(); scaleY = e1.length(); e0 /= scaleX; e1 /= scaleY; if (mgIsZero(e0.x - e1.y) && mgIsZero(e0.y + e1.x)) { isMirror = false; angle = e0.angle2(); } else { isMirror = true; angle = e0.angle2() / 2.f; reflex.x = cosf(angle); reflex.y = sinf(angle); angle = 0.f; } return true; }
bool mglnrel::crossLineBeeline( const Point2d& a, const Point2d& b, const Point2d& c, const Point2d& d, Point2d& ptCross, float* pv, const Tol& tolVec) { float u, denom, cosnum; denom = (c.x-d.x)*(b.y-a.y)-(c.y-d.y)*(b.x-a.x); if (mgIsZero(denom)) return false; cosnum = (b.x-a.x)*(d.x - c.x) + (b.y-a.y)*(d.y-c.y); if (!mgIsZero(cosnum) && fabsf(denom / cosnum) < tolVec.equalVector()) return false; u = ((c.x-a.x)*(d.y-c.y)-(c.y-a.y)*(d.x-c.x)) / denom; if (u < _MGZERO || u > 1.f - _MGZERO) return false; if (pv) { *pv = ((c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x)) / denom; } ptCross.x = (1 - u) * a.x + u * b.x; ptCross.y = (1 - u) * a.y + u * b.y; return true; }
// 计算点pt到无穷直线ab的距离 GEOMAPI float mgPtToBeeline2( const Point2d& a, const Point2d& b, const Point2d& pt, Point2d& ptPerp) { // 两点重合 if (a == b) { ptPerp = a; return a.distanceTo(pt); } // 竖直线 else if (mgIsZero(a.x - b.x)) { ptPerp.set(a.x, pt.y); return fabs(a.x - pt.x); } // 水平线 else if (mgIsZero(a.y - b.y)) { ptPerp.set(pt.x, a.y); return fabs(a.y - pt.y); } else { float t1 = ( b.y - a.y ) / ( b.x - a.x ); float t2 = -1.f / t1; ptPerp.x = ( pt.y - a.y + a.x * t1 - pt.x * t2 ) / ( t1 - t2 ); ptPerp.y = a.y + (ptPerp.x - a.x) * t1; return pt.distanceTo(ptPerp); } }
bool GiGraphics::drawEllipse(const GiContext* ctx, const Point2d& center, float rx, float ry, bool modelUnit) { if (rx < _MGZERO || isStopping()) return false; bool ret = false; Matrix2d matD(S2D(xf(), modelUnit)); if (ry < _MGZERO) { ry = (Vector2d(rx, rx) * matD).x; ry = fabsf((Vector2d(ry, ry) * matD.inverse()).y); } const Box2d extent (center, rx*2.f, ry*2.f); // 模型坐标范围 if (!DRAW_RECT(m_impl, modelUnit).isIntersect(extent)) // 全部在显示区域外 return false; if (mgIsZero(matD.m12) && mgIsZero(matD.m21)) { Point2d cen (center * matD); rx *= fabsf(matD.m11); ry *= fabsf(matD.m22); ret = rawEllipse(ctx, cen.x - rx, cen.y - ry, 2 * rx, 2 * ry); } else { Point2d pxs[13]; mgcurv::ellipseToBezier(pxs, center, rx, ry); matD.transformPoints(13, pxs); ret = rawBeziers(ctx, pxs, 13, true); } return ret; }
bool Matrix2d::hasMirror(Vector2d& reflex) const { Vector2d e0 (m11, m12); Vector2d e1 (m21, m22); if (e0.normalize() && e1.normalize() && e0.isPerpendicularTo(e1)) { if (!mgIsZero(e0.x - e1.y) || !mgIsZero(e0.y + e1.x)) { reflex.setAngleLength(e0.angle2() / 2.f, 1.f); return true; } } return false; }
void MgBaseRect::setRectWithAngle(const Point2d& pt1, const Point2d& pt2, float angle, const Point2d& basept) { Box2d rect(pt1, pt2); if (getFlag(kMgSquare)) { if (basept == pt1 && isCurve()) { rect.set(basept, 2 * basept.distanceTo(pt2), 0); } else { float len = mgMax(fabsf(pt2.x - pt1.x), fabsf(pt2.y - pt1.y)); if (basept == pt1 && !isCurve()) { rect.set(pt1, pt1 + Point2d(pt2.x > pt1.x ? len : -len, pt2.y > pt1.y ? len : -len)); } else { rect.set(basept, basept == pt1 ? 2 * len : len, 0); } } } _points[0] = rect.leftTop(); _points[1] = rect.rightTop(); _points[2] = rect.rightBottom(); _points[3] = rect.leftBottom(); if (!mgIsZero(angle)) { Matrix2d mat(Matrix2d::rotation(angle, basept)); for (int i = 0; i < 4; i++) _points[i] *= mat; } }
static bool PtInArea_Edge(int &odd, const Point2d& pt, const Point2d& p1, const Point2d& p2, const Point2d& p0) { // 如果从X方向上P不在边[P1,P2)上,则没有交点. 竖直边也没有 if (!((p2.x > p1.x) && (pt.x >= p1.x) && (pt.x < p2.x)) && !((p1.x > p2.x) && (pt.x <= p1.x) && (pt.x > p2.x)) ) { return false; } // 求从Y负无穷大向上到P的射线和该边的交点(pt.x, yy) float yy = p1.y + (pt.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x); if (pt.y > yy) // 相交 { if (mgIsZero(pt.x - p1.x)) // 交点是顶点, 则比较P[i+1]和P[i-1]是否在pt.x同侧 { if (((p0.x > pt.x) && (p2.x > pt.x)) || ((p0.x < pt.x) && (p2.x < pt.x)) ) // 同侧 { return false; } } odd = 1 - odd; // 增加一个交点, 奇偶切换 } return true; }
Matrix2d& Matrix2d::setToScaling(float scaleX, float scaleY, const Point2d& center) { if (mgIsZero(scaleY)) scaleY = scaleX; return set(scaleX, 0, 0, scaleY, (1 - scaleX) * center.x, (1 - scaleY) * center.y); }
bool GiGraphics::drawEllipse(const GiContext* ctx, const Point2d& center, float rx, float ry, bool modelUnit) { if (m_impl->drawRefcnt == 0 || rx < _MGZERO) return false; GiLock lock (&m_impl->drawRefcnt); bool ret = false; Matrix2d matD(S2D(xf(), modelUnit)); if (ry < _MGZERO) { ry = (Vector2d(rx, rx) * matD).x; ry = fabsf((Vector2d(ry, ry) * matD.inverse()).y); } const Box2d extent (center, rx*2.f, ry*2.f); // 模型坐标范围 if (!DRAW_RECT(m_impl, modelUnit).isIntersect(extent)) // 全部在显示区域外 return false; if (mgIsZero(matD.m12) && mgIsZero(matD.m21)) { Point2d cen (center * matD); rx *= fabsf(matD.m11); ry *= fabsf(matD.m22); ret = rawEllipse(ctx, cen.x - rx, cen.y - ry, 2 * rx, 2 * ry); } else { Point2d pxs[13]; mgcurv::ellipseToBezier(pxs, center, rx, ry); matD.TransformPoints(13, pxs); ret = rawBeginPath(); if (ret) { rawMoveTo(pxs[0].x, pxs[0].y); for (int i = 1; i + 2 < 13; i += 3) { rawBezierTo(pxs[i].x, pxs[i].y, pxs[i+1].x, pxs[i+1].y, pxs[i+2].x, pxs[i+2].y); } rawClosePath(); ret = rawEndPath(ctx, true); } } return ret; }
Matrix2d Matrix2d::coordSystem(const Point2d& origin, float scaleX, float scaleY, float angle) { if (mgIsZero(scaleY)) scaleY = scaleX; float s = sinf(angle); float c = cosf(angle); return Matrix2d(c*scaleX, s*scaleX, -s*scaleY, c*scaleY, origin.x, origin.y); }
bool mglnrel::crossLineAbc( float a1, float b1, float c1, float a2, float b2, float c2, Point2d& ptCross, const Tol& tolVec) { float sinnum, cosnum; sinnum = a1*b2 - a2*b1; if (mgIsZero(sinnum)) return false; cosnum = a1*a2 + b1*b2; if (!mgIsZero(cosnum) && fabsf(sinnum / cosnum) < tolVec.equalVector()) return false; ptCross.x = (b1*c2 - b2*c1) / sinnum; ptCross.y = (a2*c1 - a1*c2) / sinnum; return true; }
float MgArc::getSweepAngle() const { if (!mgIsZero(_sweepAngle)) { return _sweepAngle; } const float midAngle = (getMidPoint() - getCenter()).angle2(); const float startAngle = getStartAngle(); const float endAngle = getEndAngle(); if (mgEquals(midAngle, startAngle) && mgEquals(startAngle, endAngle)) { return endAngle - startAngle; } Tol tol(getRadius() * 1e-3f, 1e-4f); if (getStartPoint().isEqualTo(getEndPoint(), tol) && (getMidPoint() + (getStartPoint() + getEndPoint()) / 2).isEqualTo(2 * getCenter(), tol)) { return _M_2PI; } float startAngle2 = startAngle; float midAngle2 = midAngle; float endAngle2 = endAngle; // 先尝试看是否为逆时针方向:endAngle2 > midAngle2 > startAngle2 >= 0 if (startAngle2 < 0) startAngle2 += _M_2PI; while (midAngle2 < startAngle2) midAngle2 += _M_2PI; while (endAngle2 < midAngle2) endAngle2 += _M_2PI; if (fabsf(startAngle2 + endAngle2 - 2 * midAngle2) < _M_PI_6 && endAngle2 - startAngle2 < _M_2PI) { return endAngle2 - startAngle2; } // 再尝试看是否为顺时针方向:endAngle2 < midAngle2 < startAngle2 <= 0 startAngle2 = startAngle; midAngle2 = midAngle; endAngle2 = endAngle; if (startAngle2 > 0) startAngle2 -= _M_2PI; while (midAngle2 > startAngle2) midAngle2 -= _M_2PI; while (endAngle2 > midAngle2) endAngle2 -= _M_2PI; if (fabsf(startAngle2 + endAngle2 - 2 * midAngle2) < _M_PI_6) { if (endAngle2 - startAngle2 > -_M_2PI) return endAngle2 - startAngle2; return mgbase::toRange(endAngle2 - startAngle2, -_M_2PI, 0); } return endAngle - startAngle; // error }
bool mgcurv::gaussJordan(int n, float *mat, Vector2d *vs) { int i, j, k, m; float c, t; Vector2d tt; if (!mat || !vs || n < 2) return false; for (k = 0; k < n; k++) { // 找主元. 即找第k列中第k行以下绝对值最大的元素 m = k; c = mat[k*n+k]; for (i = k+1; i < n; i++) { if (fabsf(mat[i*n+k]) > fabsf(c)) { m = i; c = mat[i*n+k]; } } // 交换第k行和第m行中第k列以后的元素 if (m != k) { for (j = k; j < n; j++) { t = mat[m*n+j]; mat[m*n+j] = mat[k*n+j]; mat[k*n+j] = t; } tt = vs[m]; vs[m] = vs[k]; vs[k] = tt; } // 消元. 第k行中第k列以后元素/=mat[k][k] c = mat[k*n+k]; if (mgIsZero(c)) return false; c = 1.f / c; for (j = k; j < n; j++) mat[k*n+j] *= c; vs[k].x = vs[k].x * c; vs[k].y = vs[k].y * c; // 从第k+1行以下每一行, 对该行第k列以后各元素-= for (i = k+1; i < n; i++) { c = mat[i*n+k]; for (j = k; j < n; j++) mat[i*n+j] -= mat[k*n+j] * c; vs[i].x -= vs[k].x * c; vs[i].y -= vs[k].y * c; } } // 回代 for (i = n-2; i >= 0; i--) { for (j = i; j < n; j++) { vs[i].x -= mat[i*n+j+1] * vs[j+1].x; vs[i].y -= mat[i*n+j+1] * vs[j+1].y; } } return true; }
bool GiGraphics::drawEllipse(const GiContext* ctx, const Point2d& center, float rx, float ry, bool modelUnit) { if (m_impl->drawRefcnt == 0 || rx < _MGZERO) return false; GiLock lock (&m_impl->drawRefcnt); bool ret = false; Matrix2d matD(S2D(xf(), modelUnit)); if (ry < _MGZERO) ry = rx; const Box2d extent (center, rx*2.f, ry*2.f); // 模型坐标范围 if (!DRAW_RECT(m_impl, modelUnit).isIntersect(extent)) // 全部在显示区域外 return false; if (mgIsZero(matD.m12) && mgIsZero(matD.m21)) { Point2d cen (center * matD); rx *= matD.m11; ry *= matD.m22; ret = rawEllipse(ctx, cen.x - rx, cen.y - ry, 2 * rx, 2 * ry); } else { Point2d points[13]; mgEllipseToBezier(points, center, rx, ry); matD.TransformPoints(13, points); ret = rawBeginPath(); if (ret) { ret = rawMoveTo(points[0].x, points[0].y); ret = rawBezierTo(points + 1, 12); ret = rawClosePath(); ret = rawEndPath(ctx, true); } } return ret; }
int mgcurv::arcToBezier( Point2d points[16], const Point2d& center, float rx, float ry, float startAngle, float sweepAngle) { if (mgIsZero(rx) || fabsf(sweepAngle) < 1e-5) return 0; if (mgIsZero(ry)) ry = rx; if (sweepAngle > _M_2PI) sweepAngle = _M_2PI; else if (sweepAngle < -_M_2PI) sweepAngle = -_M_2PI; int n = 0; if (fabsf(sweepAngle) < _M_PI_2 + 1e-5) { _arcToBezier(points, center, rx, ry, startAngle, sweepAngle); n = 4; } else if (sweepAngle > 0) { startAngle = mgbase::to0_2PI(startAngle); n = _arcToBezierPlusSweep( points, center, rx, ry, startAngle, sweepAngle); } else // sweepAngle < 0 { float endAngle = startAngle + sweepAngle; sweepAngle = -sweepAngle; startAngle = mgbase::to0_2PI(endAngle); n = _arcToBezierPlusSweep( points, center, rx, ry, startAngle, sweepAngle); for (int i = 0; i < n / 2; i++) mgSwap(points[i], points[n - 1 - i]); } return n; }
// 将本矢量在两个不共线的非零矢量上进行矢量分解, vec = u*uAxis+v*vAxis bool Vector2d::resolveVector(const Vector2d& uAxis, const Vector2d& vAxis, Vector2d& uv) const { float denom = uAxis.crossProduct(vAxis); if (mgIsZero(denom)) { uv.x = 0.f; uv.y = 0.f; return false; } float c = uAxis.crossProduct(*this); uv.x = crossProduct(vAxis) / denom; uv.y = c / denom; return true; }
// 将本矢量在两个不共线的非零矢量上进行矢量分解, vec = u*uAxis+v*vAxis bool Vector2d::resolveVector(const Vector2d& uAxis, const Vector2d& vAxis, float& u, float& v) const { float denom = uAxis.crossProduct(vAxis); if (mgIsZero(denom)) { u = 0.f; v = 0.f; return false; } u = crossProduct(vAxis) / denom; v = uAxis.crossProduct(*this) / denom; return true; }
Matrix2d& Matrix2d::setToMirroring(const Point2d& pnt, const Vector2d& dir) { float d2 = dir.lengthSquare(); if (mgIsZero(d2)) setToIdentity(); else { float s2 = 2.f * dir.x * dir.y / d2; float c2 = (dir.x * dir.x - dir.y * dir.y) / d2; set(c2, s2, s2, -c2, (1 - c2) * pnt.x - s2 * pnt.y, (1 + c2) * pnt.y - s2 * pnt.x); } return *this; }
void MgBaseRect::setRect(const Box2d& rect, float angle) { _points[0] = rect.leftTop(); _points[1] = rect.rightTop(); _points[2] = rect.rightBottom(); _points[3] = rect.leftBottom(); if (!mgIsZero(angle)) { Matrix2d mat(Matrix2d::rotation(angle, rect.center())); for (int i = 0; i < 4; i++) _points[i] *= mat; } }
// 判断两个矢量是否平行 bool Vector2d::isParallelTo(const Vector2d& vec, const Tol& tol, bool& nonzero) const { bool ret = false; nonzero = true; float cosfz = dotProduct(vec); float sinfz = crossProduct(vec); if (fabsf(sinfz) <= fabsf(cosfz) * tol.equalVector()) { if (mgIsZero(cosfz)) nonzero = false; ret = true; } return ret; }
bool MgArc::setCenterStartEnd(const Point2d& center, const Point2d& start, const Point2d& end) { float startAngle = (start - center).angle2(); float endAngle = (end - center).angle2(); float sweepAngle = mgToRange(endAngle - startAngle, -_M_2PI, _M_2PI); if (!mgIsZero(sweepAngle)) { float lastSweepAngle = getSweepAngle(); if (fabsf( fabsf(sweepAngle) - fabsf(lastSweepAngle) ) > _M_PI_6) { sweepAngle = sweepAngle + (sweepAngle > 0 ? -_M_2PI : _M_2PI); } } return setCenterRadius(center, start.distanceTo(center), startAngle, sweepAngle); }
bool Matrix2d::invert() { float d = m11 * m22 - m12 * m21; if (mgIsZero(d)) { setToIdentity(); return false; } d = 1.f / d; set(m22 * d, -m12 * d, -m21 * d, m11 * d, (m21 * dy - m22 * dx) * d, (m12 * dx - m11 * dy) * d); return true; }
bool GiTransform::zoomByFactor(float factor, const Point2d* pxAt, bool adjust) { float scale = m_impl->viewScale; if (factor > 0) scale *= (1 + fabs(factor)); else scale /= (1 + fabs(factor)); if (adjust) { scale = mgMax(scale, m_impl->minViewScale); scale = mgMin(scale, m_impl->maxViewScale); } if (mgIsZero(scale - m_impl->viewScale)) return false; return zoomScale(scale, pxAt, adjust); }
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 MgBaseRect::setRect(const Point2d& pt1, const Point2d& pt2, float angle, const Point2d& basept) { Box2d rect(pt1, pt2); if (getFlag(kMgSquare)) { float len = (float)sqrt(fabs((pt2.x - pt1.x) * (pt2.y - pt1.y))); rect.set(basept, len, 0); } _points[0] = rect.leftTop(); _points[1] = rect.rightTop(); _points[2] = rect.rightBottom(); _points[3] = rect.leftBottom(); if (!mgIsZero(angle)) { Matrix2d mat(Matrix2d::rotation(angle, basept)); for (int i = 0; i < 4; i++) _points[i] *= mat; } }
bool zoomNoAdjust(const Point2d& pnt, float scale, bool* changed = NULL) { bool bChanged = false; if (pnt != centerW || !mgIsZero(scale - viewScale)) { tmpCenterW = pnt; tmpViewScale = scale; bChanged = true; if (zoomEnabled) { centerW = pnt; viewScale = scale; updateTransforms(); zoomChanged(); } } if (changed != NULL) *changed = bChanged; return bChanged; }
float GiGraphics::drawTextAt(GiTextWidthCallback* c, int argb, const char* text, const Point2d& pnt, float h, int align, float angle) { float ret = 0; if (m_impl->canvas && text && h > 0 && !m_impl->stopping && !pnt.isDegenerate()) { Point2d ptd(pnt * xf().modelToDisplay()); float w2d = xf().getWorldToDisplayY(h < 0); h = fabsf(h) * w2d; if (!mgIsZero(angle)) { angle = (Vector2d::angledVector(angle, 1) * xf().modelToWorld()).angle2(); } GiContext ctx; ctx.setFillARGB(argb ? argb : 0xFF000000); if (setBrush(&ctx)) { TextWidthCallback1 *cw = c ? new TextWidthCallback1(c, w2d) : (TextWidthCallback1 *)0; ret = m_impl->canvas->drawTextAt(cw, text, ptd.x, ptd.y, h, align, angle) / w2d; } } return ret; }