void mgcurv::roundRectToBeziers( Point2d points[16], const Box2d& rect, float rx, float ry) { if (2 * rx > rect.width()) rx = rect.width() / 2; if (2 * ry > rect.height()) ry = rect.height() / 2; int i, j; float dx = rect.width() / 2 - rx; float dy = rect.height() / 2 - ry; mgcurv::ellipseToBezier(points, rect.center(), rx, ry); for (i = 3; i >= 1; i--) { for (j = 3; j >= 0; j--) points[4 * i + j] = points[3 * i + j]; } for (i = 0; i < 4; i++) { float dx1 = (0 == i || 3 == i) ? dx : -dx; float dy1 = (0 == i || 1 == i) ? dy : -dy; for (j = 0; j < 4; j++) points[4 * i + j].offset(dx1, dy1); } }
void calcContextButtonPosition(mgvector<float>& pos, int n, const Box2d& box) { Box2d selbox(box); selbox.inflate(12, 18); if (box.height() < (n < 7 ? 40 : 80)) { selbox.deflate(0, (box.height() - (n < 7 ? 40 : 80)) / 2); } if (box.width() < (n == 3 || n > 4 ? 120 : 40)) { selbox.deflate((box.width() - (n==3||n>4 ? 120 : 40)) / 2, 0); } Box2d rect(calcButtonPosition(pos, n, selbox)); Vector2d off(moveActionsInView(rect)); for (int i = 0; i < n; i++) { pos.set(2 * i, pos.get(2 * i) + off.x, pos.get(2 * i + 1) + off.y); } }
void mgnear::moveRectHandle(Box2d& rect, int index, const Point2d& pt, bool lockCornerScale) { Point2d pts[4]; for (int i = 0; i < 4; i++) mgnear::getRectHandle(rect, index / 4 * 4 + i, pts[i]); pts[index % 4] = pt; if (index >= 0 && index < 4) { Point2d pt1(pt); if (lockCornerScale && !rect.isEmpty()) { Point2d& pt2 = pts[(index + 2) % 4]; float w = fabsf(pt2.x - pt.x); float h = fabsf(pt2.y - pt.y); if (w * rect.height() > h * rect.width()) h = w * rect.height() / rect.width(); else w = h * rect.width() / rect.height(); pt1.x = pt2.x + w * (pt2.x > pt.x ? -1.f : 1.f); pt1.y = pt2.y + h * (pt2.y > pt.y ? -1.f : 1.f); } if (index % 2 == 0) { pts[(index + 1) % 4].y = pt1.y; pts[(index + 3) % 4].x = pt1.x; } else { pts[(index + 1) % 4].x = pt1.x; pts[(index + 3) % 4].y = pt1.y; } rect.set(4, pts); } else if (index >= 4 && index < 8) { rect.set(pts[3].x, pts[2].y, pts[1].x, pts[0].y); } }
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 GiCanvasIos::drawImage(CGImageRef image, const Box2d& rectM) { CGContextRef context = m_draw->getContext(); bool ret = false; if (context && image) { Point2d ptD = rectM.center() * m_draw->xf().modelToDisplay(); Box2d rect = rectM * m_draw->xf().modelToDisplay(); CGAffineTransform af = CGAffineTransformMake(1, 0, 0, -1, 0, m_draw->height()); af = CGAffineTransformTranslate(af, ptD.x - rect.width() * 0.5f, m_draw->height() - (ptD.y + rect.height() * 0.5f)); CGContextConcatCTM(context, af); CGContextDrawImage(context, CGRectMake(0, 0, rect.width(), rect.height()), image); CGContextConcatCTM(context, CGAffineTransformInvert(af)); ret = true; } return ret; }
bool showContextActions(int /*selState*/, const int* actions, const Box2d& selbox, const MgShape*) { int n = 0; for (; actions && actions[n] > 0; n++) {} if (n > 0 && motion.pressDrag && isContextActionsVisible()) { return false; } mgvector<int> arr(actions, n); mgvector<float> pos(2 * n); calcContextButtonPosition(pos, n, selbox); return CALL_VIEW2(deviceView()->showContextActions(arr, pos, selbox.xmin, selbox.ymin, selbox.width(), selbox.height()), false); }
static void _RoundRectHit( const Box2d& rect, float rx, float ry, const Point2d& pt, float tol, const Box2d &rectTol, Point2d* pts, float& distMin, Point2d& nearpt, int& segment) { Point2d ptsBezier[13], ptTemp; Vector2d vec; float dx = rect.width() * 0.5f - rx; float dy = rect.height() * 0.5f - ry; // 按逆时针方向从第一象限到第四象限连接的四段 mgcurv::ellipseToBezier(ptsBezier, rect.center(), rx, ry); pts[3] = ptsBezier[0]; for (int i = 0; i < 4; i++) { pts[0] = pts[3]; pts[1] = ptsBezier[3 * i]; pts[2] = ptsBezier[3 * i + 1]; pts[3] = ptsBezier[3 * i + 2]; switch (i) { case 0: vec.set(dx, dy); break; case 1: vec.set(-dx, dy); break; case 2: vec.set(-dx, -dy); break; case 3: vec.set(dx, -dy); break; } for (int j = 0; j < 4; j++) pts[j] += vec; if (rectTol.isIntersect(Box2d(4, pts))) { mgnear::nearestOnBezier(pt, pts, ptTemp); float dist = pt.distanceTo(ptTemp); if (dist <= tol && dist < distMin) { distMin = dist; nearpt = ptTemp; segment = (5 - i) % 4; } } pts[3] -= vec; } }
static void AdjustCenterW(Point2d &ptW, float halfw, float halfh, const Box2d& rectW) { if (ptW.x - halfw < rectW.xmin) ptW.x += rectW.xmin - (ptW.x - halfw); if (ptW.x + halfw > rectW.xmax) ptW.x += rectW.xmax - (ptW.x + halfw); if (2 * halfw >= rectW.width()) ptW.x = rectW.center().x; if (ptW.y - halfh < rectW.ymin) ptW.y += rectW.ymin - (ptW.y - halfh); if (ptW.y + halfh > rectW.ymax) ptW.y += rectW.ymax - (ptW.y + halfh); if (2 * halfh >= rectW.height()) ptW.y = rectW.center().y; }
bool GiTransformImpl::zoomPanAdjust(Point2d &ptW, float dxPixel, float dyPixel) const { bool bAdjusted = false; float halfw = cxWnd / w2dx * 0.5f; float halfh = cyWnd / w2dy * 0.5f; if (dxPixel > 0 && ptW.x - halfw < rectLimitsW.xmin) { bAdjusted = true; ptW.x += rectLimitsW.xmin - (ptW.x - halfw); } if (dxPixel < 0 && ptW.x + halfw > rectLimitsW.xmax) { bAdjusted = true; ptW.x += rectLimitsW.xmax - (ptW.x + halfw); } if (fabs(dxPixel) > 0 && 2 * halfw >= rectLimitsW.width()) { bAdjusted = true; ptW.x = rectLimitsW.center().x; } if (dyPixel < 0 && ptW.y - halfh < rectLimitsW.ymin) { bAdjusted = true; ptW.y += rectLimitsW.ymin - (ptW.y - halfh); } if (dyPixel > 0 && ptW.y + halfh > rectLimitsW.ymax) { bAdjusted = true; ptW.y += rectLimitsW.ymax - (ptW.y + halfh); } if (fabs(dyPixel) > 0 && 2 * halfh >= rectLimitsW.height()) { bAdjusted = true; ptW.y = rectLimitsW.center().y; } return bAdjusted; }
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); }
bool GiGraphics::drawEllipse(const GiContext* ctx, const Box2d& rect, bool modelUnit) { return drawEllipse(ctx, rect.center(), rect.width() / 2, rect.height() / 2, modelUnit); }