Example #1
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 #2
0
float mgnear::cubicSplinesHit(
    int n, const Point2d* knots, const Vector2d* knotvs, bool closed, 
    const Point2d& pt, float tol, Point2d& nearpt, int& segment, bool hermite)
{
    Point2d ptTemp;
    float dist, distMin = _FLT_MAX;
    Point2d pts[4];
    const Box2d rect (pt, 2 * tol, 2 * tol);
    int n2 = (closed && n > 1) ? n + 1 : n;

    segment = -1;
    for (int i = 0; i + 1 < n2; i++) {
        mgcurv::cubicSplineToBezier(n, knots, knotvs, i, pts, hermite);
        if (rect.isIntersect(computeCubicBox(pts))) {
            dist = mgnear::nearestOnBezier(pt, pts, ptTemp);
            if (dist < distMin) {
                distMin = dist;
                nearpt = ptTemp;
                segment = i;
            }
        }
    }

    return distMin;
}
Example #3
0
float MgEllipse::_hitTest(const Point2d& pt, float tol, 
                          Point2d& nearpt, int& segment) const
{
    float distMin = _FLT_MAX;
    const Box2d rect (pt, 2 * tol, 2 * tol);
    Point2d ptTemp;

    segment = -1;
    for (int i = 0; i < 4; i++)
    {
        if (rect.isIntersect(Box2d(4, _bzpts + 3 * i)))
        {
            mgNearestOnBezier(pt, _bzpts + 3 * i, ptTemp);
            float dist = pt.distanceTo(ptTemp);
            if (dist <= tol && dist < distMin)
            {
                distMin = dist;
                nearpt = ptTemp;
                segment = i;
            }
        }
    }

    return distMin;
}
Example #4
0
float mgnear::quadSplinesHit(int n, const Point2d* knots, bool closed,
                             const Point2d& pt, float tol, Point2d& nearpt, int& segment)
{
    Point2d ptTemp;
    float dist, distMin = _FLT_MAX;
    Point2d pts[3 + 4];
    const Box2d rect (pt, 2 * tol, 2 * tol);
    
    segment = -1;
    for (int i = 0; i < (closed ? n : n - 2); i++, pts[0] = pts[2]) {
        if (i == 0) {
            pts[0] = closed ? (knots[0] + knots[1]) / 2 : knots[0];
        }
        pts[1] = knots[(i+1) % n];
        if (closed || i + 3 < n)
            pts[2] = (knots[(i+1) % n] + knots[(i+2) % n]) / 2;
        else
            pts[2] = knots[i+2];
        
        mgcurv::quadBezierToCubic(pts, pts + 3);
        if (rect.isIntersect(computeCubicBox(pts + 3))) {
            dist = mgnear::nearestOnBezier(pt, pts + 3, ptTemp);
            if (dist < distMin) {
                distMin = dist;
                nearpt = ptTemp;
                segment = i;
            }
        }
    }
    
    return distMin;
}
Example #5
0
bool mgnear::beziersIntersectBox(
    const Box2d& box, int count, const Point2d* points, bool closed)
{
    for (int i = 0; i + 3 < count; i += 3) {
        if (box.isIntersect(computeCubicBox(points + i))) {
            return true;
        }
    }
    if (closed && count > 3) {
        if (box.isIntersect(computeCubicBox(points[count - 1],
            points[count - 1] * 2 - points[count - 2].asVector(),
            points[0] * 2 - points[1].asVector(), points[0])))
        {
            return true;
        }
    }
    
    return false;
}
Example #6
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 #7
0
float mgnear::linesHit(
    int n, const Point2d* points, bool closed, 
    const Point2d& pt, float tol, Point2d& nearpt, int& segment,
    bool* inside, int* hitType)
{
    Point2d ptTemp;
    float dist, distMin = _FLT_MAX;
    const Box2d rect (pt, 2 * tol, 2 * tol);
    int n2 = (closed && n > 1) ? n + 1 : n;
    
    int type = mglnrel::ptInArea(pt, n, points, segment, Tol(tol), closed);
    
    if (inside) {
        *inside = (closed && type == mglnrel::kPtInArea);
    }
    if (hitType) {
        *hitType = type;
    }
    if (type == mglnrel::kPtAtVertex) {
        nearpt = points[segment];
        distMin = nearpt.distanceTo(pt);
        return distMin;
    }
    if (type == mglnrel::kPtOnEdge) {
        distMin = mglnrel::ptToLine(points[segment], points[(segment+1)%n], pt, nearpt);
        return distMin;
    }
    if (!closed || type != mglnrel::kPtInArea) {
        return distMin;
    }
    
    for (int i = 0; i + 1 < n2; i++)
    {
        const Point2d& pt2 = points[(i + 1) % n];
        if (closed || rect.isIntersect(Box2d(points[i], pt2)))
        {
            dist = mglnrel::ptToLine(points[i], pt2, pt, ptTemp);
            if (distMin > 1e10f || (dist <= tol && dist < distMin))
            {
                distMin = dist;
                nearpt = ptTemp;
                if (dist <= tol)
                    segment = i;
            }
        }
    }

    return distMin;
}
Example #8
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;
    }
}