Пример #1
0
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);
    }
}
Пример #2
0
    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);
        }
    }
Пример #3
0
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);
    }
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
    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);
    }
Пример #7
0
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;
    }
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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);
}
Пример #11
0
bool GiGraphics::drawEllipse(const GiContext* ctx, const Box2d& rect, bool modelUnit)
{
    return drawEllipse(ctx, rect.center(), rect.width() / 2, rect.height() / 2, modelUnit);
}