예제 #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;
}
예제 #2
0
float mglnrel::ptToBeeline2(
    const Point2d& a, const Point2d& b, const Point2d& pt, Point2d& ptPerp)
{
    // 两点重合
    if (a == b)
    {
        ptPerp = a;
        return a.distanceTo(pt);
    }
    // 竖直线
    else if (mgEquals(a.x, b.x))
    {
        ptPerp.set(a.x, pt.y);
        return fabsf(a.x - pt.x);
    }
    // 水平线
    else if (mgEquals(a.y, b.y))
    {
        ptPerp.set(pt.x, a.y);
        return fabsf(a.y - pt.y);
    }
    else
    {
        float t1 = ( b.y - a.y ) / ( b.x - a.x );
        float t2 = -1.f / t1;
        ptPerp.x = ( pt.y - a.y + a.x * t1 - pt.x * t2 ) / ( t1 - t2 );
        ptPerp.y = a.y + (ptPerp.x - a.x) * t1;
        return pt.distanceTo(ptPerp);
    }
}
예제 #3
0
파일: mgmat.cpp 프로젝트: Vito2015/vgcore
Matrix2d Matrix2d::transformWith2P(const Point2d& from1, const Point2d& from2,
                                   const Point2d& to1, const Point2d& to2)
{
    if (from1 == from2 || to1 == to2
        || from1.isDegenerate() || from2.isDegenerate() || to1.isDegenerate() || to2.isDegenerate()) {
        return Matrix2d::kIdentity();
    }
    return (translation(to1 - from1)
            * scaling(to2.distanceTo(to1) / from2.distanceTo(from1), to1)
            * rotation((to2 - to1).angle2() - (from2 - from1).angle2(), to1));
}
예제 #4
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;
}
예제 #5
0
void MgBaseRect::setRectWithAngle(const Point2d& pt1, const Point2d& pt2,
                                  float angle, const Point2d& basept)
{
    Box2d rect(pt1, pt2);
    
    if (getFlag(kMgSquare)) {
        if (basept == pt1 && isCurve()) {
            rect.set(basept, 2 * basept.distanceTo(pt2), 0);
        }
        else {
            float len = mgMax(fabsf(pt2.x - pt1.x), fabsf(pt2.y - pt1.y));
            if (basept == pt1 && !isCurve()) {
                rect.set(pt1, pt1 + Point2d(pt2.x > pt1.x ? len : -len,
                                            pt2.y > pt1.y ? len : -len));
            } else {
                rect.set(basept, basept == pt1 ? 2 * len : len, 0);
            }
        }
    }
    
    _points[0] = rect.leftTop();
    _points[1] = rect.rightTop();
    _points[2] = rect.rightBottom();
    _points[3] = rect.leftBottom();

    if (!mgIsZero(angle))
    {
        Matrix2d mat(Matrix2d::rotation(angle, basept));
        for (int i = 0; i < 4; i++)
            _points[i] *= mat;
    }
}
예제 #6
0
파일: mgarc.cpp 프로젝트: Vito2015/vgcore
float MgArc::_hitTest(const Point2d& pt, float tol, MgHitResult& res) const
{
    Point2d points[16];
    int n = mgcurv::arcToBezier(points, getCenter(), getRadius(), 0, getStartAngle(), getSweepAngle());

    float dist, distMin = _FLT_MAX;
    Point2d ptTemp;

    if (_subtype > 0) {
        dist = mglnrel::ptToLine(getCenter(), getStartPoint(), pt, ptTemp);
        if (dist <= tol && dist < distMin) {
            distMin = dist;
            res.nearpt = ptTemp;
        }
        dist = mglnrel::ptToLine(getCenter(), getEndPoint(), pt, ptTemp);
        if (dist <= tol && dist < distMin) {
            distMin = dist;
            res.nearpt = ptTemp;
        }
    }
    for (int i = 0; i + 3 < n; i += 3) {
        mgnear::nearestOnBezier(pt, points + i, ptTemp);
        dist = pt.distanceTo(ptTemp);
        if (dist <= tol && dist < distMin) {
            distMin = dist;
            res.nearpt = ptTemp;
        }
    }
    
    return distMin;
}
예제 #7
0
파일: mgpath.cpp 프로젝트: Vito2015/vgcore
 virtual bool processLine(int, int&, const Point2d& startpt, const Point2d& endpt) {
     if (box.contains(Box2d(startpt, endpt))
         && mglnrel::cross2Line(startpt, endpt, a, b, tmpcross)) {
         dist = tmpcross.distanceTo(box.center());
         if (mindist > dist) {
             mindist = dist;
             crosspt = tmpcross;
         }
     }
     return true;
 }
예제 #8
0
float mglnrel::ptToLine(
    const Point2d& a, const Point2d& b, const Point2d& pt, Point2d& nearpt)
{
    Point2d ptTemp;
    float dist = mglnrel::ptToBeeline2(a, b, pt, nearpt);
    if (!mglnrel::isBetweenLine3(a, b, nearpt, &ptTemp))
    {
        nearpt = ptTemp;
        dist = pt.distanceTo(nearpt);
    }
    return dist;
}
예제 #9
0
파일: mgpath.cpp 프로젝트: Vito2015/vgcore
 virtual bool processLine(int startIndex, int &endIndex, const Point2d& startpt, const Point2d& endpt) {
     if (pt.distanceTo(endpt) <= dist) {
         p->points[startIndex] = endpt;
         p->points.erase(p->points.begin() + endIndex);
         p->types.erase(p->types.begin() + endIndex);
         --endIndex;
     } else {
         p->points[startIndex] = pt.rulerPoint(endpt, dist, 0);
         return false;
     }
     return true;
 }
예제 #10
0
bool MgCmdDrawLines::checkClosed(const MgMotion* sender, const Point2d& pnt)
{
    bool closed = false;
    MgBaseLines* lines = (MgBaseLines*)dynshape()->shape();
    
    if ((m_index == 0 || m_index == m_step) && needCheckClosed()) {
        float distmin = sender->displayMmToModel(2.f);
        closed = m_step > 2 && pnt.distanceTo(m_index == 0 ? lines->endPoint()
                                              : lines->getPoint(0)) < distmin;
        lines->setClosed(closed);
    }
    
    return closed;
}
예제 #11
0
int mglnrel::ptInArea(
    const Point2d& pt, int count, const Point2d* pts, 
    int& order, const Tol& tol, bool closed)
{
    int i;
    int odd = 1;    // 1: 交点数为偶数, 0: 交点数为奇数
    float minDist = tol.equalPoint();
    Point2d nearpt;
    
    order = -1;
    for (i = 0; i < count && tol.equalPoint() < 1.e5f; i++)
    {
        // P与某顶点重合. 返回 kPtAtVertex, order = 顶点号 [0, count-1]
        float d = pt.distanceTo(pts[i]);
        if (minDist > d) {
            minDist = d;
            order = i;
        }
    }
    if (order >= 0) {
        return kPtAtVertex;
    }
    
    order = -1;
    minDist = tol.equalPoint();
    
    for (i = 0; i < (closed ? count : count - 1); i++)
    {
        const Point2d& p1 = pts[i];
        const Point2d& p2 = (i+1 < count) ? pts[i+1] : pts[0];
        
        // P在某条边上. 返回 kPtOnEdge, order = 边号 [0, count-1]
        float d = mglnrel::ptToBeeline2(p1, p2, pt, nearpt);
        if (minDist > d) {
            minDist = d;
            order = i;
        }
        else if (!PtInArea_Edge(odd, pt, p1, p2, 
                                i > 0 ? pts[i-1] : pts[count-1])) {
            continue;
        }
    }
    if (order >= 0) {
        return kPtOnEdge;
    }

    // 如果射线和多边形的交点数为偶数, 则 p==1, P在区外, 返回 kPtOutArea
    // 为奇数则p==0, P在区内, 返回 kPtInArea
    return 0 == odd ? kPtInArea : kPtOutArea;
}
예제 #12
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)
            }
        }
    }
}
예제 #13
0
파일: mgpath.cpp 프로젝트: Vito2015/vgcore
 virtual bool processBezier(int, int&, const Point2d* pts) {
     float t = 0;
     
     if (box.contains(Box2d(4, pts))
         && mgcurv::bezierIntersectionWithLine(pts, a, b, t)) {
         mgcurv::fitBezier(pts, t, tmpcross);
         dist = tmpcross.distanceTo(box.center());
         if (mindist > dist) {
             mindist = dist;
             crosspt = tmpcross;
         }
     }
     return true;
 }
예제 #14
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;
}
예제 #15
0
bool MgArc::setCenterStartEnd(const Point2d& center, const Point2d& start, const Point2d& end)
{
    float startAngle = (start - center).angle2();
    float endAngle = (end - center).angle2();
    float sweepAngle = mgToRange(endAngle - startAngle, -_M_2PI, _M_2PI);

    if (!mgIsZero(sweepAngle)) {
        float lastSweepAngle = getSweepAngle();
        if (fabsf( fabsf(sweepAngle) - fabsf(lastSweepAngle) ) > _M_PI_6) {
            sweepAngle = sweepAngle + (sweepAngle > 0 ?  -_M_2PI :  _M_2PI);
        }
    }

    return setCenterRadius(center, start.distanceTo(center), startAngle, sweepAngle);
}
예제 #16
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;
    }
}
예제 #17
0
파일: mgarc.cpp 프로젝트: Vito2015/vgcore
bool MgArc::setCSE(const Point2d& center, const Point2d& start, 
                   const Point2d& end, float lastSweepAngle)
{
    float startAngle = (start - center).angle2();
    float endAngle = (end - center).angle2();
    float sweepAngle = mgbase::toRange(endAngle - startAngle, -_M_2PI, _M_2PI);
    
    if (fabsf(sweepAngle - lastSweepAngle) > _M_PI) {
        if (fabsf(sweepAngle) < _M_D2R * 5 && fabsf(lastSweepAngle) > _M_PI + _M_PI_2) {
            sweepAngle = lastSweepAngle > 0 ? _M_2PI : -_M_2PI;
        } else {
            sweepAngle = sweepAngle + (sweepAngle > 0 ?  -_M_2PI :  _M_2PI);
        }
    }

    return setCenterRadius(center, start.distanceTo(center), startAngle, sweepAngle);
}
예제 #18
0
float MgArc::_hitTest(const Point2d& pt, float tol, 
                      Point2d& nearpt, int&) const
{
    Point2d points[16];
    int n = mgAngleArcToBezier(points, getCenter(), getRadius(), 0, getStartAngle(), getSweepAngle());

    float distMin = _FLT_MAX;
    Point2d ptTemp;

    for (int i = 0; i + 3 < n; i += 3) {
        mgNearestOnBezier(pt, points + i, ptTemp);
        float dist = pt.distanceTo(ptTemp);
        if (dist <= tol && dist < distMin) {
            distMin = dist;
            nearpt = ptTemp;
        }
    }
    
    return distMin;
}
예제 #19
0
bool MgCmdDrawLines::canAddPoint(const MgMotion* sender, bool ended)
{
    float minDist = mgDisplayMmToModel(3, sender);
    Point2d endPt  = m_shape->shape()->getPoint(m_step - 1);
    float distToEnd = endPt.distanceTo(sender->pointM);
    float turnAngle = 90;
    
    if (m_step > 1)
    {
        Point2d lastPt = m_shape->shape()->getPoint(m_step - 2);
        turnAngle = (endPt - lastPt).angleTo(sender->pointM - endPt);
        turnAngle = mgRad2Deg(fabs(turnAngle));
    }
    
    if (distToEnd < minDist * (ended ? 0.25 : 1))
        return false;
    if (!ended && sin(turnAngle) * distToEnd < 5)
        return false;
    
    return true;
}
예제 #20
0
void TransformCmd::setPointW(int index, const MgMotion* sender)
{
    Point2d point = sender->point * sender->view->xform()->displayToWorld();
    
    if (index > 0) {
        float a = (point - _origin).angle2();
        float len = _origin.distanceTo(point);
        a = floorf(0.5f + a * _M_R2D / 5) * 5 * _M_D2R;
        len = floorf(0.5f + len / 5) * 5;
        _axis[index == 1 ? 0 : 1].setAngleLength(a, len);
        
        Matrix2d mat(_axis[0], _axis[1], _origin * sender->view->xform()->worldToModel());
        mat *= _xfFirst.inverse();
        mat = sender->view->shapes()->modelTransform() * mat;
        
        sender->view->xform()->setModelTransform(mat);
        sender->view->regen();
    } else {
        _origin = point;
        sender->view->redraw(true);
    }
}
예제 #21
0
파일: mgarc.cpp 프로젝트: Vito2015/vgcore
bool MgArc::_setHandlePoint2(int index, const Point2d& pt, float, int& data)
{
    static float lastSweepAngle;
    
    if (index == 1 || index == 2) {     // 起点、终点
        return setCenterRadius(getCenter(), pt.distanceTo(getCenter()), getStartAngle(), getSweepAngle());
    }
    if (index == 3) {                   // 弧线中点
        return setStartMidEnd(getStartPoint(), pt, getEndPoint());
    }
    if (index == 4) {                   // 改变起始角度
        if (data == 0) {
            lastSweepAngle = getSweepAngle();
            data++;
        }
        Point2d startPt(getCenter().polarPoint((pt - getCenter()).angle2(), getRadius()));
        bool ret = setCSE(getCenter(), startPt, getEndPoint(), lastSweepAngle);
        lastSweepAngle = getSweepAngle();
        return ret;
    }
    if (index == 5) {                   // 改变终止角度
        if (data == 0) {
            lastSweepAngle = getSweepAngle();
            data++;
        }
        Point2d endPt(getCenter().polarPoint((pt - getCenter()).angle2(), getRadius()));
        bool ret = setCSE(getCenter(), getStartPoint(), endPt, lastSweepAngle);
        lastSweepAngle = getSweepAngle();
        return ret;
    }
    if (index == 6) {
        return setTanStartEnd(pt - getStartPoint(), getStartPoint(), getEndPoint());
    }
    if (index == 7) {
        return (setTanStartEnd(getEndPoint() - pt, getEndPoint(), getStartPoint())
            && _reverse());
    }
    return offset(pt - getCenter(), -1);
}
예제 #22
0
bool MgBaseRect::_setHandlePoint(int index, const Point2d& pt, float)
{
    if (getFlag(kMgSquare)) {
        if (isCurve() && !isEmpty(_MGZERO)) {
            float olddist = _getHandlePoint(index).distanceTo(getCenter());
            transform(Matrix2d::scaling(pt.distanceTo(getCenter()) / olddist, getCenter()));
        }
        else {
            Matrix2d mat(Matrix2d::rotation(-getAngle(), getCenter()));
            Point2d pt2(pt * mat);
            Box2d rect(getRect());
            mgnear::moveRectHandle(rect, index, pt2);
            
            if (4 == index || 6 == index) {
                rect = Box2d(rect.center(), rect.height(), rect.height());
            }
            else {
                rect = Box2d(rect.center(), rect.width(), rect.width());
            }
            setRectWithAngle(rect.leftTop(), rect.rightBottom(), getAngle(), 
                             rect.center() * mat.inverse());
        }
    }
    else {
        int index2 = index / 4 * 4 + (index % 4 + 2) % 4;
        Point2d corner(_getHandlePoint(index2));
        Matrix2d mat(Matrix2d::rotation(-getAngle(), corner));
        
        Box2d rect(_getHandlePoint(0) * mat, _getHandlePoint(2) * mat);
        Point2d pt2(pt * mat);
        
        mgnear::moveRectHandle(rect, index, pt2);
        setRectWithAngle(rect.leftTop(), rect.rightBottom(), getAngle(), corner);
    }
    update();
    return true;
}
예제 #23
0
파일: mgarc.cpp 프로젝트: Vito2015/vgcore
bool MgArc::setCenterStartEnd(const Point2d& center, const Point2d& start)
{
    float startAngle = (start - center).angle2();
    return setCenterRadius(center, start.distanceTo(center), startAngle, 0);
}
예제 #24
0
bool MgEllipse::setCircle2P(const Point2d& start, const Point2d& end)
{
    return setCircle((start + end) / 2, start.distanceTo(end) / 2);
}
예제 #25
0
파일: mgpath.cpp 프로젝트: Vito2015/vgcore
 virtual bool processLine(int, int&, const Point2d& startpt, const Point2d& endpt) {
     length += startpt.distanceTo(endpt);
     return true;
 }
예제 #26
0
float MgDot::_hitTest(const Point2d& pt, float, MgHitResult& res) const
{
    res.nearpt = _point;
    return pt.distanceTo(_point);
}