bool GiGraphics::drawRect(const GiContext* ctx, const Box2d& rect, bool modelUnit) { if (rect.isEmpty() && ctx && m_impl->canvas) { rawRect(ctx, 0, 0, 0, 0); return false; } Point2d points[4] = { rect.leftBottom(), rect.rightBottom(), rect.rightTop(), rect.leftTop() }; return !rect.isEmpty() && drawPolygon(ctx, 4, points, modelUnit); }
Box2d GiTransform::setWorldLimits(const Box2d& rect) { Box2d ret = m_impl->rectLimitsW; m_impl->rectLimitsW = rect.isEmpty() ? Box2d(Point2d::kOrigin(), 2e5f, 2e5f) : rect; m_impl->rectLimitsW.normalize(); return ret; }
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::drawRoundRect(const GiContext* ctx, const Box2d& rect, float rx, float ry, bool modelUnit) { if (m_impl->drawRefcnt == 0 || rect.isEmpty()) return false; GiLock lock (&m_impl->drawRefcnt); bool ret = false; if (ry < _MGZERO) ry = rx; if (!DRAW_RECT(m_impl, modelUnit).isIntersect(rect)) // 全部在显示区域外 return false; if (rx < _MGZERO) { Point2d points[4] = { rect.leftBottom(), rect.rightBottom(), rect.rightTop(), rect.leftTop() }; return drawPolygon(ctx, 4, points); } else { Point2d points[16]; mgRoundRectToBeziers(points, rect, rx, ry); S2D(xf(), modelUnit).TransformPoints(16, points); ret = rawBeginPath(); if (ret) { ret = rawMoveTo(points[0].x, points[0].y); ret = rawBezierTo(&points[1], 3); ret = rawLineTo(points[4].x, points[4].y); ret = rawBezierTo(&points[5], 3); ret = rawLineTo(points[8].x, points[8].y); ret = rawBezierTo(&points[9], 3); ret = rawLineTo(points[12].x, points[12].y); ret = rawBezierTo(&points[13], 3); ret = rawClosePath(); ret = rawEndPath(ctx, true); } } return ret; }
void MgCmdManagerImpl::getBoundingBox(Box2d& box, const MgMotion* sender) { MgCommand* cmd = sender->cmds()->getCommand(); Box2d selbox; if (cmd && strcmp(cmd->getName(), MgCmdSelect::Name()) == 0) { MgCmdSelect* sel = (MgCmdSelect*)cmd; selbox = sel->getBoundingBox(sender); } box = selbox.isEmpty() ? Box2d(sender->pointM, 0, 0) : selbox; box *= sender->view->xform()->modelToDisplay(); box.normalize(); }
bool GiGraphics::drawRoundRect(const GiContext* ctx, const Box2d& rect, float rx, float ry, bool modelUnit) { if (rect.isEmpty() || isStopping()) return false; bool ret = false; if (ry < _MGZERO) ry = rx; if (!DRAW_RECT(m_impl, modelUnit).isIntersect(rect)) // 全部在显示区域外 return false; if (rx < _MGZERO) { Point2d points[4] = { rect.leftBottom(), rect.rightBottom(), rect.rightTop(), rect.leftTop() }; return drawPolygon(ctx, 4, points); } else { Point2d pxs[16]; mgcurv::roundRectToBeziers(pxs, rect, rx, ry); S2D(xf(), modelUnit).transformPoints(16, pxs); ret = rawBeginPath(); if (ret) { rawMoveTo(pxs[0].x, pxs[0].y); rawBezierTo(pxs[1].x, pxs[1].y, pxs[2].x, pxs[2].y, pxs[3].x, pxs[3].y); rawLineTo(pxs[4].x, pxs[4].y); rawBezierTo(pxs[5].x, pxs[5].y, pxs[6].x, pxs[6].y, pxs[7].x, pxs[7].y); rawLineTo(pxs[8].x, pxs[8].y); rawBezierTo(pxs[9].x, pxs[9].y, pxs[10].x, pxs[10].y, pxs[11].x, pxs[11].y); rawLineTo(pxs[12].x, pxs[12].y); rawBezierTo(pxs[13].x, pxs[13].y, pxs[14].x, pxs[14].y, pxs[15].x, pxs[15].y); rawClosePath(); ret = rawEndPath(ctx, true); } } return ret; }
static bool AdjustCenterIn(bool adjust, const Box2d& box, const Box2d& limitsW, Point2d &ptW, float halfw, float halfh) { Box2d rectW(limitsW); rectW.inflate(2); if (!limitsW.isEmpty() && !rectW.contains(box)) { if (adjust) { AdjustCenterW(ptW, halfw, halfh, rectW); } else { return false; } } return true; }
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); } }
Vector2d moveActionsInView(Box2d& rect) { Vector2d off; Box2d viewrect(0.f, 0.f, (float)xform()->getWidth(), (float)xform()->getHeight()); if (!rect.isEmpty() && !viewrect.contains(rect)) { if (rect.xmin < 0) { off.x = -rect.xmin; } else if (rect.xmax > viewrect.xmax) { off.x = viewrect.xmax - rect.xmax; } if (rect.ymin < 0) { off.y = -rect.ymin; } else if (rect.ymax > viewrect.ymax) { off.y = viewrect.ymax - rect.ymax; } } return off; }
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 giPrintSetup(GiTransform& xf, HDC hdc, const Box2d& rectShow, bool bWorldRect, const RECT* margin, float scale, float offsetX, float offsetY) { if (hdc == NULL || rectShow.isEmpty()) return false; int dpix = GetDeviceCaps(hdc, LOGPIXELSX); // 每英寸的像素数 int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); // 每英寸的像素数 int width = GetDeviceCaps(hdc, PHYSICALWIDTH); // 页面宽,像素 int height = GetDeviceCaps(hdc, PHYSICALHEIGHT); // 页面高,像素 int cx = GetDeviceCaps(hdc, HORZRES); // 可打印宽度,像素 int cy = GetDeviceCaps(hdc, VERTRES); // 可打印高度,像素 int ml = GetDeviceCaps(hdc, PHYSICALOFFSETX); // 左最小边距,像素 int mt = GetDeviceCaps(hdc, PHYSICALOFFSETY); // 上最小边距,像素 int mr = width - cx - ml; // 右最小边距,像素 int mb = height - cy - mt; // 下最小边距,像素 RECT rc = { 0, 0, cx, cy }; // 纸上打印范围,像素 if (margin != NULL) // 指定了页边距 { int n; if (ml < (n = MulDiv(margin->left, dpix, 2540))) rc.left += n - ml; if (mt < (n = MulDiv(margin->top, dpiy, 2540))) rc.top += n - mt; if (mr < (n = MulDiv(margin->right, dpix, 2540))) rc.right -= n - mr; if (mb < (n = MulDiv(margin->bottom, dpiy, 2540))) rc.bottom -= n - mb; if (rc.right - rc.left < 10) { rc.left = 0; rc.right = cx; } if (rc.bottom - rc.top < 10) { rc.top = 0; rc.bottom = cy; } } ::InflateRect(&rc, -1, -1); // 缩小纸上打印范围,以便放缩后不丢失像素 xf.setWndSize(cx, cy); xf.setResolution((float)dpix, (float)dpiy); Box2d rectShowW = rectShow; if (!bWorldRect) rectShowW *= xf.modelToWorld(); Box2d rectOld = xf.setWorldLimits(Box2d()); RECT2D rc2d(giConvertRect(rc)); bool ret = xf.zoomTo(rectShowW, &rc2d, true); if (scale >= xf.getMinViewScale() && scale <= xf.getMaxViewScale()) { ret = ret && xf.zoomScale(scale, NULL, true); xf.zoom(xf.getCenterW() - Vector2d(offsetX, offsetY), xf.getViewScale()); } xf.setWorldLimits(rectOld); return ret; }
bool MgCmdManagerImpl::showInSelect(const MgMotion* sender, int selState, const MgShape* shape, const Box2d& selbox) { if (sender->view->getCmdSubject()->selectActionsNeedHided(sender)) { return false; } int actions[12]; int n = 0; bool isslines = (shape && selState == kMgSelOneShape && shape->shapec()->isKindOf(kMgShapeSplines)); bool isOpenLines = (shape && selState == kMgSelOneShape && shape->shapec()->isKindOf(kMgShapeLines) && !shape->shapec()->isClosed()); bool locked = shape && shape->shapec()->getFlag(kMgShapeLocked); bool fixedLength = shape && shape->shapec()->getFlag(kMgFixedLength); switch (selState) { case kMgSelNone: break; case kMgSelMultiShapes: if (shape && shape->getParent() && shape->getParent()->getOwner()->isKindOf(kMgShapeDoc)) { actions[n++] = kMgActionGroup; } case kMgSelOneShape: if (!locked && !sender->view->useFinger()) { actions[n++] = kMgActionDelete; } actions[n++] = kMgActionClone; if (!locked && shape && (shape->shapec()->isKindOf(kMgShapeImage) || shape->shapec()->isKindOf(kMgShapeLine))) { actions[n++] = fixedLength ? kMgActionFreeLength : kMgActionFixedLength; } actions[n++] = locked ? kMgActionUnlocked : kMgActionLocked; if (selState == kMgSelOneShape && !locked) { actions[n++] = kMgActionEditVertex; } else { //actions[n++] = kMgActionSelReset; } if (selState == kMgSelOneShape && shape && shape->shapec()->isClosed() && !shape->shapec()->getFlag(kMgRotateDisnable) && !shape->shapec()->getFlag(kMgShapeLocked) && (shape->shapec()->isKindOf(kMgShapeParallel) || shape->shapec()->isKindOf(kMgShapeLines)) ) { actions[n++] = kMgActionOverturn; } break; case kMgSelVertexes: if ((isslines || isOpenLines) && shape && !shape->shapec()->getFlag(kMgShapeLocked)) { //actions[n++] = closed ? kMgActionOpened : kMgActionClosed; actions[n++] = kMgActionAddVertex; } if (!locked && shape && shape->shapec()->isKindOf(kMgShapeLine)) { actions[n++] = fixedLength ? kMgActionFreeLength : kMgActionFixedLength; } //actions[n++] = locked ? kMgActionUnlocked : kMgActionLocked; actions[n++] = kMgActionHideVertex; break; case kMgSelVertex: if ((isslines || isOpenLines) && shape && !shape->shapec()->getFlag(kMgShapeLocked)) { //actions[n++] = closed ? kMgActionOpened : kMgActionClosed; actions[n++] = kMgActionDelVertex; } if (!locked && shape && shape->shapec()->isKindOf(kMgShapeLine)) { actions[n++] = fixedLength ? kMgActionFreeLength : kMgActionFixedLength; } //actions[n++] = locked ? kMgActionUnlocked : kMgActionLocked; actions[n++] = kMgActionHideVertex; break; case kMgSelDraw: break; } if (selState > kMgSelNone && selState <= kMgSelVertex && shape) { mgvector<int> arr(actions, sizeof(actions)/sizeof(actions[0])); n = sender->view->getCmdSubject()->addShapeActions(sender, arr, n, shape); for (int i = 0; i < n; i++) { actions[i] = arr.get(i); } if (shape->shapec()->isKindOf(kMgShapeGroup) && sender->view->shapeCanUngroup(shape)) { actions[n++] = kMgActionUngroup; } } actions[n++] = 0; if (!selbox.isEmpty()) { sender->view->redraw(); } Box2d box(selbox.isEmpty() ? Box2d(sender->pointM, 0, 0) : selbox); box *= sender->view->xform()->modelToDisplay(); return sender->view->showContextActions(selState, actions, box, shape); }