float GiGraphics::calcPenWidth(float lineWidth, bool useViewScale) const { float w = 1; float px; if (m_impl->maxPenWidth <= 1) lineWidth = 0; if (lineWidth > 0) // 单位:0.01mm { px = lineWidth / 2540.f * xf().getDpiY(); if (useViewScale) px *= xf().getViewScale(); w = mgMin(px, m_impl->maxPenWidth); } else if (lineWidth < 0) // 单位:像素 { w = mgMin(-lineWidth, m_impl->maxPenWidth); } w = mgMax(w, m_impl->minPenWidth); if (lineWidth <= 0 && xf().getDpiY() > getScreenDpi()) { w = w * xf().getDpiY() / getScreenDpi(); } return w; }
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; }
float GiGraphics::calcPenWidth(float lineWidth, bool useViewScale) const { float w = mgMin(m_impl->minPenWidth, 1.f); if (m_impl->maxPenWidth <= 1) lineWidth = 0; if (lineWidth > 0) { // 单位:0.01mm w = lineWidth / 2540.f * xf().getDpiY(); if (useViewScale) w *= xf().getViewScale(); } else if (lineWidth < 0) { // 单位:像素 if (lineWidth < -1e3f) // 不使用UI放缩系数 w = 1e3f - lineWidth; else w = -lineWidth * _penWidthFactor; if (useViewScale) w *= xf().getViewScale(); } w = mgMin(w, m_impl->maxPenWidth); w = mgMax(w, m_impl->minPenWidth); //if (lineWidth <= 0 && xf().getDpiY() > getScreenDpi()) // w = w * xf().getDpiY() / getScreenDpi(); return w; }
float mgnear::roundRectHit( const Box2d& rect, float rx, float ry, const Point2d& pt, float tol, Point2d& nearpt, int& segment) { rx = fabsf(rx); if (ry < _MGZERO) ry = rx; rx = mgMin(rx, rect.width() * 0.5f); ry = mgMin(ry, rect.height() * 0.5f); segment = -1; Point2d ptTemp, ptTemp2; float dist, distMin = _FLT_MAX; Point2d pts[8]; const Box2d rectTol (pt, 2 * tol, 2 * tol); // 顶边上的两个圆弧切点,左,右 pts[0] = RoundRectTan(0, 1, rect, rx); pts[1] = RoundRectTan(1, 0, rect, rx); // 右边上的两个圆弧切点,上,下 pts[2] = RoundRectTan(1, 2, rect, ry); pts[3] = RoundRectTan(2, 1, rect, ry); // 底边上的两个圆弧切点,右,左 pts[4] = RoundRectTan(2, 3, rect, rx); pts[5] = RoundRectTan(3, 2, rect, rx); // 左边上的两个圆弧切点,下,上 pts[6] = RoundRectTan(3, 0, rect, ry); pts[7] = RoundRectTan(0, 3, rect, ry); for (int i = 0; i < 4; i++) { Box2d rcLine (pts[2 * i], pts[2 * i + 1]); if (rcLine.isEmpty() || rectTol.isIntersect(rcLine)) { dist = mglnrel::ptToLine(pts[2 * i], pts[2 * i + 1], pt, ptTemp); if (dist <= tol && dist < distMin) { distMin = dist; nearpt = ptTemp; segment = 4 + i; } } } if (rx > _MGZERO && ry > _MGZERO) { _RoundRectHit(rect, rx, ry, pt, tol, rectTol, pts, distMin, nearpt, segment); } return distMin; }
bool GiGraphics::drawBSplines(const GiContext* ctx, int count, const Point2d* ctlpts, bool closed, bool modelUnit) { if (closed) { if (count < 3 || !ctlpts || isStopping()) return false; count = mgMin(count, static_cast<int>((0x2000 - 1) / 3)); } else { if (count < 4 || !ctlpts || isStopping()) return false; count = mgMin(count, static_cast<int>(3 + (0x2000 - 1) / 3)); } const Box2d extent (count, ctlpts); // 模型坐标范围 if (!DRAW_RECT(m_impl, modelUnit).isIntersect(extent)) // 全部在显示区域外 return false; int i; Point2d pt1, pt2, pt3, pt4; float d6 = 1.f / 6.f; vector<Point2d> pxpoints; Matrix2d matD(S2D(xf(), modelUnit)); // 开辟像素坐标数组 pxpoints.resize(1 + (closed ? count : (count - 3)) * 3); Point2d *pxs = &pxpoints.front(); // 计算第一个曲线段 pt1 = ctlpts[0] * matD; pt2 = ctlpts[1] * matD; pt3 = ctlpts[2] * matD; pt4 = ctlpts[3 % count] * matD; (*pxs++).set((pt1.x + 4 * pt2.x + pt3.x)*d6, (pt1.y + 4 * pt2.y + pt3.y)*d6); (*pxs++).set((4 * pt2.x + 2 * pt3.x) *d6, (4 * pt2.y + 2 * pt3.y) *d6); (*pxs++).set((2 * pt2.x + 4 * pt3.x) *d6, (2 * pt2.y + 4 * pt3.y) *d6); (*pxs++).set((pt2.x + 4 * pt3.x + pt4.x)*d6, (pt2.y + 4 * pt3.y + pt4.y)*d6); // 计算其余曲线段 for (i = 4; i < (closed ? (count + 3) : count); i++) { pt1 = pt2; pt2 = pt3; pt3 = pt4; pt4 = ctlpts[i % count] * matD; (*pxs++).set((4 * pt2.x + 2 * pt3.x) *d6, (4 * pt2.y + 2 * pt3.y) *d6); (*pxs++).set((2 * pt2.x + 4 * pt3.x) *d6, (2 * pt2.y + 4 * pt3.y) *d6); (*pxs++).set((pt2.x + 4 * pt3.x + pt4.x)*d6,(pt2.y + 4 * pt3.y + pt4.y)*d6); } // 绘图 return rawBeziers(ctx, &pxpoints.front(), getSize(pxpoints), closed); }
static void snapGrid(const MgMotion*, const Point2d& orignPt, const MgShape* shape, int ignoreHandle, const MgShape* sp, SnapItem arr[3], Point2d* matchpt) { if (sp->shapec()->isKindOf(MgGrid::Type())) { Point2d newPt (orignPt); const MgGrid* grid = (const MgGrid*)(sp->shapec()); Point2d dists(arr[1].dist, arr[2].dist); int type = grid->snap(newPt, dists); if (type & 1) { arr[1].base = newPt; arr[1].pt = newPt; arr[1].type = kMgSnapGridX; arr[1].dist = dists.x; } if (type & 2) { arr[2].base = newPt; arr[2].pt = newPt; arr[2].type = kMgSnapGridY; arr[2].dist = dists.y; } int d = matchpt ? shape->shapec()->getHandleCount() - 1 : -1; for (; d >= 0; d--) { if (d == ignoreHandle || shape->shapec()->isHandleFixed(d)) continue; Point2d ptd (shape->shapec()->getHandlePoint(d)); dists.set(mgMin(arr[0].dist, arr[1].dist), mgMin(arr[0].dist, arr[2].dist)); newPt = ptd; type = grid->snap(newPt, dists); float dist = newPt.distanceTo(ptd); if ((type & 3) == 3 && arr[0].dist > dist - _MGZERO) { arr[0].dist = dist; arr[0].base = ptd; arr[0].pt = newPt; arr[0].type = kMgSnapGrid; arr[0].shapeid = sp->getID(); arr[0].handleIndex = -1; arr[0].handleIndexSrc = d; // 因为对当前图形先从startM移到pointM,然后再从pointM移到matchpt *matchpt = orignPt + (newPt - ptd); // 所以最后差量为(pnt-ptd) } } } }
void GiTransform::setViewScaleRange(float minScale, float maxScale) { if (minScale > maxScale) mgSwap(minScale, maxScale); minScale = mgMax(minScale, 1e-5f); minScale = mgMin(minScale, 0.5f); maxScale = mgMax(maxScale, 1.f); maxScale = mgMin(maxScale, 50.f); m_impl->minViewScale = minScale; m_impl->maxViewScale = maxScale; }
float MgEllipse::_hitTest(const Point2d& pt, float tol, MgHitResult& res) const { if (isCircle()) { Point2d pt1(getCenter()), pt2(pt); crossCircle(pt1, pt2, this); float d1 = pt.distanceTo(pt1); float d2 = pt.distanceTo(pt2); res.nearpt = d1 < d2 ? pt1 : pt2; return mgMin(d1, d2); } float distMin = _FLT_MAX; const Box2d rect (pt, 2 * tol, 2 * tol); Point2d ptTemp; for (int i = 0; i < 4; i++) { if (rect.isIntersect(Box2d(4, _bzpts + 3 * i))) { mgnear::nearestOnBezier(pt, _bzpts + 3 * i, ptTemp); float dist = pt.distanceTo(ptTemp); if (dist <= tol && dist < distMin) { distMin = dist; res.nearpt = ptTemp; res.segment = i; } } } return distMin; }
static int angleToBezier_(Point2d* pts, float radius) { const Vector2d vec1 (pts[1] - pts[0]); // 第一条边 const Vector2d vec2 (pts[2] - pts[1]); // 第二条边 const float dHalfAngle = 0.5f * fabsf(vec1.angleTo2(vec2)); // 夹角的一半 if (dHalfAngle < 1e-4f || fabsf(dHalfAngle - _M_PI_2) < 1e-4f) // 两条边平行 return 0; const float dDist1 = 0.5f * vec1.length(); const float dDist2 = 0.5f * vec2.length(); float dArc = radius / tan(dHalfAngle); // 圆弧在边上的投影长度 if (dArc > dDist1 || dArc > dDist2) { float dArcOld = dArc; dArc = mgMin(dDist1, dDist2); if (dArc < dArcOld * 0.5f) return 3; } int count = 0; Point2d ptCenter, ptStart, ptEnd; float startAngle, sweepAngle; ptStart = pts[1].rulerPoint(pts[0], dArc, 0); ptEnd = pts[1].rulerPoint(pts[2], dArc, 0); if (mgcurv::arcTan(ptStart, ptEnd, pts[1] - ptStart, ptCenter, radius, &startAngle, &sweepAngle)) { count = mgcurv::arcToBezier( pts, ptCenter, radius, radius, startAngle, sweepAngle); } return count; }
bool MgCmdDrawLines::touchBegan(const MgMotion* sender) { Point2d pnt(snapPoint(sender, true)); MgBaseLines* lines = (MgBaseLines*)dynshape()->shape(); if (0 == m_step) { m_step = 1; m_index = 1; lines->resize(2); dynshape()->shape()->setPoint(0, pnt); dynshape()->shape()->setPoint(1, pnt); } else { if (m_step >= dynshape()->shape()->getPointCount()) { if (m_step > 2) { lines->addPoint(pnt); m_step = mgMin(m_step, lines->getPointCount() - 1); m_index = m_step; } else { lines->addPoint(pnt); m_index = m_step; } } dynshape()->shape()->setPoint(m_index, pnt); } dynshape()->shape()->update(); _lastClicked = true; return MgCommandDraw::touchBegan(sender); }
bool GiGraphics::drawSplines(const GiContext* ctx, int count, const Point2d* knots, const Vector2d* knotvs, bool modelUnit) { if (m_impl->drawRefcnt == 0 || count < 2 || knots == NULL || knotvs == NULL) return false; GiLock lock (&m_impl->drawRefcnt); count = mgMin(count, static_cast<int>(1 + (0x2000 - 1) / 3)); int i; Point2d pt; Vector2d vec; vector<Point2d> pxpoints; Matrix2d matD(S2D(xf(), modelUnit)); // 开辟整形像素坐标数组 pxpoints.resize(1 + (count - 1) * 3); Point2d *pxs = &pxpoints.front(); pt = knots[0] * matD; // 第一个Bezier段的起点 vec = knotvs[0] * matD / 3.f; // 第一个Bezier段的起始矢量 *pxs++ = pt; // 产生Bezier段的起点 for (i = 1; i < count; i++) // 计算每一个Bezier段 { *pxs++ = (pt += vec); // 产生Bezier段的第二点 pt = knots[i] * matD; // Bezier段的终点 vec = knotvs[i] * matD / 3.f; // Bezier段的终止矢量 *pxs++ = pt - vec; // 产生Bezier段的第三点 *pxs++ = pt; // 产生Bezier段的终点 } // 绘图 return rawBeziers(ctx, &pxpoints.front(), getSize(pxpoints)); }
bool GiGraphics::drawHermiteSplines(const GiContext* ctx, int count, const Point2d* knots, const Vector2d* knotvs, bool closed, bool modelUnit) { if (count < 2 || !knots || !knotvs || isStopping()) return false; count = mgMin(count, 0x1000); int i; Point2d pt; Vector2d vec; vector<Point2d> pxpoints; Matrix2d matD(S2D(xf(), modelUnit)); Matrix2d mat2(matD / 3.f); pxpoints.resize(1 + (closed ? count : count - 1) * 3); Point2d *pxs = &pxpoints.front(); pt = knots[0] * matD; // 第一个Bezier段的起点 vec = knotvs[0] * mat2; // 第一个Bezier段的起始矢量 *pxs++ = pt; // 产生Bezier段的起点 for (i = 1; i < count; i++) { // 计算每一个Bezier段 *pxs++ = (pt += vec); // 产生Bezier段的第二点 pt = knots[i] * matD; // Bezier段的终点 vec = knotvs[i] * mat2; // Bezier段的终止矢量 *pxs++ = pt - vec; // 产生Bezier段的第三点 *pxs++ = pt; // 产生Bezier段的终点 } if (closed) { *pxs++ = (pt += vec); // 产生Bezier段的第二点 *pxs++ = 2 * pxpoints[0] - pxpoints[1].asVector(); // 产生Bezier段的第三点 *pxs++ = pxpoints[0]; // 产生Bezier段的终点 } return rawBeziers(ctx, &pxpoints.front(), getSize(pxpoints), closed); }
bool GiGraphics::drawClosedBSplines(const GiContext* ctx, int count, const Point2d* ctlpts, bool modelUnit) { if (m_impl->drawRefcnt == 0 || count < 3 || ctlpts == NULL) return false; GiLock lock (&m_impl->drawRefcnt); count = mgMin(count, static_cast<int>((0x2000 - 1) / 3)); const Box2d extent (count, ctlpts); // 模型坐标范围 if (!DRAW_RECT(m_impl, modelUnit).isIntersect(extent)) // 全部在显示区域外 return false; int i; Point2d pt1, pt2, pt3, pt4; float d6 = 1.f / 6.f; vector<Point2d> pxpoints; Matrix2d matD(S2D(xf(), modelUnit)); // 开辟整形像素坐标数组 pxpoints.resize(1 + count * 3); Point2d *pxs = &pxpoints.front(); // 计算第一个曲线段 pt1 = ctlpts[0] * matD; pt2 = ctlpts[1] * matD; pt3 = ctlpts[2] * matD; pt4 = ctlpts[3 % count] * matD; (*pxs++).set((pt1.x + 4 * pt2.x + pt3.x)*d6, (pt1.y + 4 * pt2.y + pt3.y)*d6); (*pxs++).set((4 * pt2.x + 2 * pt3.x) *d6, (4 * pt2.y + 2 * pt3.y) *d6); (*pxs++).set((2 * pt2.x + 4 * pt3.x) *d6, (2 * pt2.y + 4 * pt3.y) *d6); (*pxs++).set((pt2.x + 4 * pt3.x + pt4.x)*d6, (pt2.y + 4 * pt3.y + pt4.y)*d6); // 计算其余曲线段 for (i = 4; i < count + 3; i++) { pt1 = pt2; pt2 = pt3; pt3 = pt4; pt4 = ctlpts[i % count] * matD; (*pxs++).set((4 * pt2.x + 2 * pt3.x) *d6, (4 * pt2.y + 2 * pt3.y) *d6); (*pxs++).set((2 * pt2.x + 4 * pt3.x) *d6, (2 * pt2.y + 4 * pt3.y) *d6); (*pxs++).set((pt2.x + 4 * pt3.x + pt4.x)*d6, (pt2.y + 4 * pt3.y + pt4.y)*d6); } // 绘图 bool ret = rawBeginPath(); if (ret) { ret = rawMoveTo(pxs[0].x, pxs[0].y); ret = rawBezierTo(pxs + 1, getSize(pxpoints) - 1); ret = rawClosePath(); ret = rawEndPath(ctx, true); } return ret; }
bool GiTransform::zoomScale(float viewScale, const Point2d* pxAt, bool adjust) { // 检查显示比例 if (!adjust && ScaleOutRange(viewScale, m_impl)) return false; viewScale = mgMax(viewScale, m_impl->minViewScale); viewScale = mgMin(viewScale, m_impl->maxViewScale); // 得到放缩中心点的客户区坐标 Point2d ptAt (m_impl->cxWnd * 0.5f, m_impl->cyWnd * 0.5f); if (pxAt != NULL) ptAt.set(pxAt->x, pxAt->y); // 得到放缩中心点在放缩前的世界坐标 Point2d ptAtW (ptAt * m_impl->matD2W); // 计算新显示比例下显示窗口中心的世界坐标 Point2d ptW; float w2dx = m_impl->w2dx / m_impl->viewScale * viewScale; float w2dy = m_impl->w2dy / m_impl->viewScale * viewScale; ptW.x = ptAtW.x + (m_impl->cxWnd * 0.5f - ptAt.x) / w2dx; ptW.y = ptAtW.y - (m_impl->cyWnd * 0.5f - ptAt.y) / w2dy; // 检查新显示比例下显示窗口的世界坐标范围是否在极限范围内 float halfw = m_impl->cxWnd / w2dx * 0.5f; float halfh = m_impl->cyWnd / w2dy * 0.5f; Box2d box (ptW, 2 * halfw, 2 * halfh); if (!AdjustCenterIn(adjust, box, m_impl->rectLimitsW, ptW, halfw, halfh)) { return false; } if (halfw - 3 > m_impl->rectLimitsW.width() / 2 && halfh - 3 > m_impl->rectLimitsW.height() / 2) // 显示比例太小 { viewScale *= mgMin(2 * (halfw - 3) / m_impl->rectLimitsW.width(), 2 * (halfh - 3) / m_impl->rectLimitsW.height()); viewScale = mgMin(viewScale, m_impl->maxViewScale); } return m_impl->zoomNoAdjust(ptW, viewScale); }
bool GiTransform::zoom(Point2d centerW, float viewScale, bool* changed) { viewScale = mgMax(viewScale, m_impl->minViewScale); viewScale = mgMin(viewScale, m_impl->maxViewScale); if (!m_impl->rectLimitsW.isEmpty()) { float halfw = m_impl->cxWnd / m_impl->w2dx * 0.5f; float halfh = m_impl->cyWnd / m_impl->w2dy * 0.5f; if (centerW.x - halfw < m_impl->rectLimitsW.xmin) centerW.x += m_impl->rectLimitsW.xmin - (centerW.x - halfw); if (centerW.x + halfw > m_impl->rectLimitsW.xmax) centerW.x += m_impl->rectLimitsW.xmax - (centerW.x + halfw); if (2 * halfw >= m_impl->rectLimitsW.width()) centerW.x = m_impl->rectLimitsW.center().x; if (centerW.y - halfh < m_impl->rectLimitsW.ymin) centerW.y += m_impl->rectLimitsW.ymin - (centerW.y - halfh); if (centerW.y + halfh > m_impl->rectLimitsW.ymax) centerW.y += m_impl->rectLimitsW.ymax - (centerW.y + halfh); if (2 * halfh >= m_impl->rectLimitsW.height()) centerW.y = m_impl->rectLimitsW.center().y; // 如果显示比例很小使得窗口超界,就放大显示 if (2 * halfw > m_impl->rectLimitsW.width() && 2 * halfh > m_impl->rectLimitsW.height()) { viewScale *= mgMin(2 * halfw / m_impl->rectLimitsW.width(), 2 * halfh / m_impl->rectLimitsW.height()); if (viewScale > m_impl->maxViewScale) viewScale = m_impl->maxViewScale; } } m_impl->zoomNoAdjust(centerW, viewScale, changed); return true; }
bool GiGraphics::drawClosedSplines(const GiContext* ctx, int count, const Point2d* knots, const Vector2d* knotvs, bool modelUnit) { if (m_impl->drawRefcnt == 0 || count < 2 || knots == NULL || knotvs == NULL) return false; GiLock lock (&m_impl->drawRefcnt); count = mgMin(count, static_cast<int>((0x2000 - 1) / 3)); int i, j = 0; Point2d pt; Vector2d vec; vector<Point2d> pxpoints; Matrix2d matD(S2D(xf(), modelUnit)); // 开辟像素坐标数组 pxpoints.resize(1 + count * 3); Point2d *pxs = &pxpoints.front(); pt = knots[0] * matD; // 第一个Bezier段的起点 vec = knotvs[0] * matD / 3.f; // 第一个Bezier段的起始矢量 pxs[j++] = pt; // 产生Bezier段的起点 for (i = 1; i < count; i++) // 计算每一个Bezier段 { pxs[j++] = (pt += vec); // 产生Bezier段的第二点 pt = knots[i] * matD; // Bezier段的终点 vec = knotvs[i] * matD / 3.f; // Bezier段的终止矢量 pxs[j++] = pt - vec; // 产生Bezier段的第三点 pxs[j++] = pt; // 产生Bezier段的终点 } pxs[j++] = (pt += vec); // 产生Bezier段的第二点 pxs[j] = 2 * pxs[0] - pxs[1].asVector(); // 产生Bezier段的第三点 pxs[j+1] = pxs[0]; // 产生Bezier段的终点 // 绘图 bool ret = rawBeginPath(); if (ret) { rawMoveTo(pxs[0].x, pxs[0].y); for (i = 1; i + 2 < getSize(pxpoints); 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; }
// ConvertToBezierForm : // Given a point and a Bezier curve, generate a 5th-degree // Bezier-format equation whose solution finds the point on the // curve nearest the user-defined point. // Parameters : // pt: The point to find t for // pts: The control points // w: Ctl pts of 5th-degree curve, [W_DEGREE+1] // static void ConvertToBezierForm(const Point2d& pt, const Point2d* pts, Point2d* w) { int i, j, k, m, n, ub, lb; int row, column; // Table indices Vector2d c[DEGREE+1]; // pts(i)'s - pt Vector2d d[DEGREE]; // pts(i+1) - pts(i) float cdTable[3][4]; // Dot product of c, d const float z[3][4] = { // Precomputed "z" for cubics {1.0f, 0.6f, 0.3f, 0.1f}, {0.4f, 0.6f, 0.6f, 0.4f}, {0.1f, 0.3f, 0.6f, 1.0f}, }; // Determine the c's -- these are vectors created by subtracting // point pt from each of the control points for (i = 0; i <= DEGREE; i++) { c[i] = pts[i] - pt; } // Determine the d's -- these are vectors created by subtracting // each control point from the next for (i = 0; i <= DEGREE - 1; i++) { d[i] = 3.f * (pts[i+1] - pts[i]); } // Create the c,d table -- this is a table of dot products of the // c's and d's for (row = 0; row <= DEGREE - 1; row++) { for (column = 0; column <= DEGREE; column++) { cdTable[row][column] = d[row].dotProduct(c[column]); } } // Now, apply the z's to the dot products, on the skew diagonal // Also, set up the x-values, making these "points" for (i = 0; i <= W_DEGREE; i++) { w[i].y = 0.f; w[i].x = static_cast<float>(i) / W_DEGREE; } n = DEGREE; m = DEGREE-1; for (k = 0; k <= n + m; k++) { lb = mgMax(0, k - m); ub = mgMin(k, n); for (i = lb; i <= ub; i++) { j = k - i; w[i+j].y += cdTable[j][i] * z[j][i]; } } }
bool GiTransform::zoom(Point2d centerW, float viewScale) { bool changed = false; viewScale = mgMax(viewScale, m_impl->minViewScale); viewScale = mgMin(viewScale, m_impl->maxViewScale); Box2d rectW(m_impl->rectLimitsW); rectW.inflate(2); float halfw = m_impl->cxWnd / m_impl->w2dx * 0.5f; float halfh = m_impl->cyWnd / m_impl->w2dy * 0.5f; if (centerW.x - halfw < rectW.xmin) centerW.x += rectW.xmin - (centerW.x - halfw); if (centerW.x + halfw > rectW.xmax) centerW.x += rectW.xmax - (centerW.x + halfw); if (2 * halfw >= rectW.width()) centerW.x = rectW.center().x; if (centerW.y - halfh < rectW.ymin) centerW.y += rectW.ymin - (centerW.y - halfh); if (centerW.y + halfh > rectW.ymax) centerW.y += rectW.ymax - (centerW.y + halfh); if (2 * halfh >= rectW.height()) centerW.y = rectW.center().y; // 如果显示比例很小使得窗口超界,就放大显示 if (2 * halfw > rectW.width() && 2 * halfh > rectW.height()) { viewScale *= mgMin(2 * halfw / rectW.width(), 2 * halfh / rectW.height()); if (viewScale > m_impl->maxViewScale) viewScale = m_impl->maxViewScale; } m_impl->zoomNoAdjust(centerW, viewScale, &changed); return changed; }
bool GiTransform::zoomByFactor(float factor, const Point2d* pxAt, bool adjust) { float scale = m_impl->viewScale; if (factor > 0) scale *= (1.f + fabsf(factor)); else scale /= (1.f + fabsf(factor)); if (adjust) { scale = mgMax(scale, m_impl->minViewScale); scale = mgMin(scale, m_impl->maxViewScale); } if (mgEquals(scale, m_impl->viewScale)) return false; return zoomScale(scale, pxAt, adjust); }
bool GiTransform::zoomWnd(const Point2d& pt1, const Point2d& pt2, bool adjust) { // 计算开窗矩形的中心和宽高 Point2d ptCen ((pt2.x + pt1.x) * 0.5f, (pt2.y + pt1.y) * 0.5f); float w = fabs(static_cast<float>(pt2.x - pt1.x)); float h = fabs(static_cast<float>(pt2.y - pt1.y)); if (w < 4 || h < 4) return false; // 中心不变,扩大开窗矩形使得宽高比例和显示窗口相同 if (h * m_impl->cxWnd > w * m_impl->cyWnd) w = h * m_impl->cxWnd / m_impl->cyWnd; else h = w * m_impl->cyWnd / m_impl->cxWnd; // 计算放缩前矩形中心的世界坐标 Point2d ptW (ptCen * m_impl->matD2W); // 计算新显示比例 float scale = m_impl->viewScale * m_impl->cyWnd / h; if (!adjust && ScaleOutRange(scale, m_impl)) return false; scale = mgMax(scale, m_impl->minViewScale); scale = mgMin(scale, m_impl->maxViewScale); // 计算新显示比例下的显示窗口的世界坐标范围 float halfw = m_impl->cxWnd / (m_impl->w2dx / m_impl->viewScale * scale) * 0.5f; float halfh = m_impl->cyWnd / (m_impl->w2dy / m_impl->viewScale * scale) * 0.5f; Box2d box (ptW, 2 * halfw, 2 * halfh); // 检查显示窗口的新坐标范围是否在极限范围内 if (!m_impl->rectLimitsW.isEmpty() && !m_impl->rectLimitsW.contains(box)) { if (adjust) AdjustCenterW(ptW, halfw, halfh, m_impl->rectLimitsW); else return false; } // 改变显示比例和位置 return m_impl->zoomNoAdjust(ptW, scale); }
bool MgDiamond::_setHandlePoint(UInt32 index, const Point2d& pt, float tol) { if (!getFlag(kMgFixedLength)) { return MgBaseRect::_setHandlePoint(4 + index % 4, pt, tol); } Point2d cen(getCenter()); Point2d pnt, ptup, ptside; pnt = pt * Matrix2d::rotation(-getAngle(), cen); mgGetRectHandle(getRect(), 4 + (index + 2) % 4, ptup); mgGetRectHandle(getRect(), 4 + (index + 1) % 4, ptside); float len = ptup.distanceTo(ptside); float dy = index % 2 == 0 ? pnt.y - ptup.y : pnt.x - ptup.x; float ry = mgMin(len, (float)fabs(dy) / 2); float rx = (float)sqrt(len * len - ry * ry); Box2d rect(cen, rx * 2, ry * 2); setRect(rect.leftTop(), rect.rightBottom(), getAngle(), cen); return true; }
bool GiTransform::zoomScale(float viewScale, const Point2d* pxAt, bool adjust) { // 检查显示比例 if (!adjust && ScaleOutRange(viewScale, m_impl)) return false; viewScale = mgMax(viewScale, m_impl->minViewScale); viewScale = mgMin(viewScale, m_impl->maxViewScale); // 得到放缩中心点的客户区坐标 Point2d ptAt (m_impl->cxWnd * 0.5f, m_impl->cyWnd * 0.5f); if (pxAt != NULL) ptAt.set(pxAt->x, pxAt->y); // 得到放缩中心点在放缩前的世界坐标 Point2d ptAtW (ptAt * m_impl->matD2W); // 计算新显示比例下显示窗口中心的世界坐标 Point2d ptW; float w2dx = m_impl->w2dx / m_impl->viewScale * viewScale; float w2dy = m_impl->w2dy / m_impl->viewScale * viewScale; ptW.x = ptAtW.x + (m_impl->cxWnd * 0.5f - ptAt.x) / w2dx; ptW.y = ptAtW.y - (m_impl->cyWnd * 0.5f - ptAt.y) / w2dy; // 检查新显示比例下显示窗口的世界坐标范围是否在极限范围内 float halfw = m_impl->cxWnd / w2dx * 0.5f; float halfh = m_impl->cyWnd / w2dy * 0.5f; Box2d box (ptW, 2 * halfw, 2 * halfh); if (!m_impl->rectLimitsW.isEmpty() && !m_impl->rectLimitsW.contains(box)) { if (adjust) AdjustCenterW(ptW, halfw, halfh, m_impl->rectLimitsW); else return false; } return m_impl->zoomNoAdjust(ptW, viewScale); }
bool GiTransform::zoomTo(const Box2d& rectWorld, const RECT_2D* rcTo, bool adjust) { // 如果图形范围的宽或高接近于零,就返回 if (rectWorld.isEmpty()) return false; // 计算像素到毫米的比例 const float d2mmX = m_impl->viewScale / m_impl->w2dx; const float d2mmY = m_impl->viewScale / m_impl->w2dy; // 计算目标窗口区域(毫米) float w = 0, h = 0; Point2d ptCen; if (rcTo != NULL) { w = fabsf(static_cast<float>(rcTo->right - rcTo->left)); h = fabsf(static_cast<float>(rcTo->bottom - rcTo->top)); ptCen.x = (rcTo->left + rcTo->right) * 0.5f; ptCen.y = (rcTo->top + rcTo->bottom) * 0.5f; } if (w < 4 || h < 4) { w = (float)m_impl->cxWnd; h = (float)m_impl->cyWnd; ptCen.set(w * 0.5f, h * 0.5f); w -= 8; h -= 8; } if (w < 4 || h < 4) return false; w *= d2mmX; h *= d2mmY; ptCen.scaleBy(d2mmX, d2mmY); // 计算新显示比例 (中心不变,缩小窗口区域使得宽高比例和图形范围相同) float scale; if (h * rectWorld.width() > w * rectWorld.height()) { //h = w * rectWorld.height() / rectWorld.width(); scale = w / rectWorld.width(); } else { //w = h * rectWorld.width() / rectWorld.height(); scale = h / rectWorld.height(); } // 检查显示比例 if (!adjust && ScaleOutRange(scale, m_impl)) return false; scale = mgMax(scale, m_impl->minViewScale); scale = mgMin(scale, m_impl->maxViewScale); // 计算在新显示比例下显示窗口中心的世界坐标 Point2d ptW; ptW.x = rectWorld.center().x + (m_impl->cxWnd * d2mmX * 0.5f - ptCen.x) / scale; ptW.y = rectWorld.center().y - (m_impl->cyWnd * d2mmY * 0.5f - ptCen.y) / scale; // 检查新显示比例下显示窗口的世界坐标范围是否在极限范围内 float halfw = m_impl->cxWnd * d2mmX / scale * 0.5f; float halfh = m_impl->cyWnd * d2mmY / scale * 0.5f; Box2d box (ptW, 2 * halfw, 2 * halfh); if (!AdjustCenterIn(adjust, box, m_impl->rectLimitsW, ptW, halfw, halfh)) { return false; } return m_impl->zoomNoAdjust(ptW, scale); }
// ControlPolygonFlatEnough : // Check if the control polygon of a Bezier curve is flat enough // for recursive subdivision to bottom out. // Parameters : // pts: Control pts // degree: Degree of bezier curve // static int ControlPolygonFlatEnough(const Point2d* pts, int degree) { int i; // Index variable float distance[W_DEGREE+1]; // Distances from pts to line float max_distance_above; // maximum of these float max_distance_below; float error; // Precision of root float intercept_1, intercept_2, left_intercept, right_intercept; float a, b, c; // Coefficients of implicit eqn for line from pts[0]-pts[deg] // Find the perpendicular distance // from each interior control point to // line connecting pts[0] and pts[degree] { float abSquared; // Derive the implicit equation for line connecting first *' // and last control points a = pts[0].y - pts[degree].y; b = pts[degree].x - pts[0].x; c = pts[0].x * pts[degree].y - pts[degree].x * pts[0].y; abSquared = (a * a) + (b * b); for (i = 1; i < degree; i++) { // Compute distance from each of the points to that line distance[i] = a * pts[i].x + b * pts[i].y + c; if (distance[i] > 0.0) { distance[i] = (distance[i] * distance[i]) / abSquared; } if (distance[i] < 0.0) { distance[i] = -((distance[i] * distance[i]) / abSquared); } } } // Find the largest distance max_distance_above = 0.0; max_distance_below = 0.0; for (i = 1; i < degree; i++) { if (distance[i] < 0.0) { max_distance_below = mgMin(max_distance_below, distance[i]); }; if (distance[i] > 0.0) { max_distance_above = mgMax(max_distance_above, distance[i]); } } { float det, dInv; float a1, b1, c1, a2, b2, c2; // Implicit equation for zero line a1 = 0.0; b1 = 1.0; c1 = 0.0; // Implicit equation for "above" line a2 = a; b2 = b; c2 = c + max_distance_above; det = a1 * b2 - a2 * b1; dInv = 1 / det; intercept_1 = (b1 * c2 - b2 * c1) * dInv; // Implicit equation for "below" line a2 = a; b2 = b; c2 = c + max_distance_below; det = a1 * b2 - a2 * b1; dInv = 1 / det; intercept_2 = (b1 * c2 - b2 * c1) * dInv; } // Compute intercepts of bounding box left_intercept = mgMin(intercept_1, intercept_2); right_intercept = mgMax(intercept_1, intercept_2); error = 0.5f * (right_intercept-left_intercept); if (error < _MGZERO) { return 1; } else { return 0; } }