Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #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;
}
Example #5
0
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);
}
Example #6
0
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)
            }
        }
    }
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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;
}
Example #10
0
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);
}
Example #11
0
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));
}
Example #12
0
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);
}
Example #13
0
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;
}
Example #14
0
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);
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
0
// 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];
        }
    }
}
Example #18
0
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;
}
Example #19
0
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);
}
Example #20
0
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);
}
Example #21
0
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;
}
Example #22
0
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);
}
Example #23
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);
}
Example #24
0
// 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;
    }
}