<commit_before>// mgpathsp.cpp: 实现路径图形 MgPathShape
// Copyright (c) 2004-2014, <NAME>
// License: LGPL, https://github.com/touchvg/vgcore

#include "mgpathsp.h"
#include "mgshape_.h"
#include <sstream>

MG_IMPLEMENT_CREATE(MgPathShape)

MgPathShape::MgPathShape()
{
}

MgPathShape::~MgPathShape()
{
}

int MgPathShape::_getPointCount() const
{
    return _path.getCount();
}

Point2d MgPathShape::_getPoint(int index) const
{
    return _path.getPoint(index);
}

void MgPathShape::_setPoint(int index, const Point2d& pt)
{
    _path.setPoint(index, pt);
}

void MgPathShape::_copy(const MgPathShape& src)
{
    _path.copy(src._path);
    __super::_copy(src);
}

bool MgPathShape::_equals(const MgPathShape& src) const
{
    if (_path.getCount() != src._path.getCount() || !__super::_equals(src)) {
        return false;
    }
    for (int i = 0; i < _path.getCount(); i++) {
        if (_path.getPoint(i) != src._path.getPoint(i) ||
            _path.getNodeType(i) != src._path.getNodeType(i)) {
            return false;
        }
    }
    return true;
}

void MgPathShape::_update()
{
    _extent.set(_path.getCount(), _path.getPoints());
    __super::_update();
}

void MgPathShape::_transform(const Matrix2d& mat)
{
    for (int i = 0; i < _path.getCount(); i++) {
        _path.setPoint(i, _path.getPoint(i) * mat);
    }
    __super::_transform(mat);
}

void MgPathShape::_clear()
{
    _path.clear();
    __super::_clear();
}

bool MgPathShape::_isClosed() const
{
    return !!(_path.getNodeType(_path.getCount() - 1) & kGiCloseFigure);
}

bool MgPathShape::isCurve() const
{
    for (int i = 0; i < _path.getCount(); i++) {
        if (_path.getNodeType(i) & (kGiBezierTo | kGiQuadTo))
            return true;
    }
    return false;
}

float MgPathShape::_hitTest(const Point2d& pt, float tol, MgHitResult& res) const
{
    int n = _path.getCount();
    const Point2d* pts = _path.getPoints();
    const char* types = _path.getTypes();
    Point2d pos, ends, bz[7], nearpt;
    bool err = false;
    const Box2d rect (pt, 2 * tol, 2 * tol);
    
    res.dist = _FLT_MAX - tol;
    for (int i = 0; i < n && !err; i++) {
        float dist = _FLT_MAX;
        pos = ends;
        
        switch (types[i] & ~kGiCloseFigure) {
            case kGiMoveTo:
                ends = pts[i];
                break;
                
            case kGiLineTo:
                ends = pts[i];
                if (rect.isIntersect(Box2d(pos, ends))) {
                    dist = mglnrel::ptToLine(pos, ends, pt, nearpt);
                }
                break;
                
            case kGiBezierTo:
                if (i + 2 >= n) {
                    err = true;
                    break;
                }
                bz[0] = pos;
                bz[1] = pts[i];
                bz[2] = pts[i+1];
                bz[3] = pts[i+2];
                ends = bz[3];
                
                if (rect.isIntersect(mgnear::bezierBox1(bz))) {
                    dist = mgnear::nearestOnBezier(pt, bz, nearpt);
                }
                i += 2;
                break;
                
            case kGiQuadTo:
                if (i + 1 >= n) {
                    err = true;
                    break;
                }
                bz[0] = pos;
                bz[1] = pts[i];
                bz[2] = pts[i+1];
                ends = bz[2];
                
                mgcurv::quadBezierToCubic(bz, bz + 3);
                if (rect.isIntersect(mgnear::bezierBox1(bz + 3))) {
                    dist = mgnear::nearestOnBezier(pt, bz, nearpt);
                }
                i++;
                break;
                
            default:
                err = true;
                break;
        }
        if (res.dist > dist) {
            res.dist = dist;
            res.segment = i;
            res.nearpt = nearpt;
        }
    }
    
    return res.dist;
}

bool MgPathShape::_hitTestBox(const Box2d& rect) const
{
    if (!__super::_hitTestBox(rect))
        return false;
    
    int n = _path.getCount();
    const Point2d* pts = _path.getPoints();
    const char* types = _path.getTypes();
    Point2d pos, ends, bz[7];
    int ret = 0;
    
    for (int i = 0; i < n && !ret; i++) {
        pos = ends;
        
        switch (types[i] & ~kGiCloseFigure) {
            case kGiMoveTo:
                ends = pts[i];
                break;
                
            case kGiLineTo:
                ends = pts[i];
                ret = rect.isIntersect(Box2d(pos, ends));
                break;<commit_msg>Call linesHit in MgPathShape::_hitTest().<commit_after>// mgpathsp.cpp: 实现路径图形 MgPathShape
// Copyright (c) 2004-2014, <NAME>
// License: LGPL, https://github.com/touchvg/vgcore

#include "mgpathsp.h"
#include "mgshape_.h"
#include "vector"
#include <sstream>

MG_IMPLEMENT_CREATE(MgPathShape)

MgPathShape::MgPathShape()
{
}

MgPathShape::~MgPathShape()
{
}

int MgPathShape::_getPointCount() const
{
    return _path.getCount();
}

Point2d MgPathShape::_getPoint(int index) const
{
    return _path.getPoint(index);
}

void MgPathShape::_setPoint(int index, const Point2d& pt)
{
    _path.setPoint(index, pt);
}

void MgPathShape::_copy(const MgPathShape& src)
{
    _path.copy(src._path);
    __super::_copy(src);
}

bool MgPathShape::_equals(const MgPathShape& src) const
{
    if (_path.getCount() != src._path.getCount() || !__super::_equals(src)) {
        return false;
    }
    for (int i = 0; i < _path.getCount(); i++) {
        if (_path.getPoint(i) != src._path.getPoint(i) ||
            _path.getNodeType(i) != src._path.getNodeType(i)) {
            return false;
        }
    }
    return true;
}

void MgPathShape::_update()
{
    _extent.set(_path.getCount(), _path.getPoints());
    __super::_update();
}

void MgPathShape::_transform(const Matrix2d& mat)
{
    for (int i = 0; i < _path.getCount(); i++) {
        _path.setPoint(i, _path.getPoint(i) * mat);
    }
    __super::_transform(mat);
}

void MgPathShape::_clear()
{
    _path.clear();
    __super::_clear();
}

bool MgPathShape::_isClosed() const
{
    return !!(_path.getNodeType(_path.getCount() - 1) & kGiCloseFigure);
}

bool MgPathShape::isCurve() const
{
    for (int i = 0; i < _path.getCount(); i++) {
        if (_path.getNodeType(i) & (kGiBezierTo | kGiQuadTo))
            return true;
    }
    return false;
}

float MgPathShape::_hitTest(const Point2d& pt, float tol, MgHitResult& res) const
{
    int n = _path.getCount();
    const Point2d* pts = _path.getPoints();
    const char* types = _path.getTypes();
    Point2d pos, ends, bz[7], nearpt;
    bool err = false;
    const Box2d rect (pt, 2 * tol, 2 * tol);
    std::vector<Point2d> edges;
    
    res.dist = _FLT_MAX - tol;
    for (int i = 0; i < n && !err; i++) {
        float dist = _FLT_MAX;
        pos = ends;
        
        switch (types[i] & ~kGiCloseFigure) {
            case kGiMoveTo:
                ends = pts[i];
                break;
                
            case kGiLineTo:
                ends = pts[i];
                if (rect.isIntersect(Box2d(pos, ends))) {
                    dist = mglnrel::ptToLine(pos, ends, pt, nearpt);
                }
                break;
                
            case kGiBezierTo:
                if (i + 2 >= n) {
                    err = true;
                    break;
                }
                bz[0] = pos;
                bz[1] = pts[i];
                bz[2] = pts[i+1];
                bz[3] = pts[i+2];
                ends = bz[3];
                
                if (rect.isIntersect(mgnear::bezierBox1(bz))) {
                    dist = mgnear::nearestOnBezier(pt, bz, nearpt);
                }
                i += 2;
                break;
                
            case kGiQuadTo:
                if (i + 1 >= n) {
                    err = true;
                    break;
                }
                bz[0] = pos;
                bz[1] = pts[i];
                bz[2] = pts[i+1];
                ends = bz[2];
                
                mgcurv::quadBezierToCubic(bz, bz + 3);
                if (rect.isIntersect(mgnear::bezierBox1(bz + 3))) {
                    dist = mgnear::nearestOnBezier(pt, bz, nearpt);
                }
                i++;
                break;
                
            default:
                err = true;
                break;
        }
        edges.push_back(ends);
        if (res.dist > dist) {
            res.dist = dist;
            res.segment = i;
            res.nearpt = nearpt;
        }
    }
    if (isClosed() && edges.size() > 2) {
        MgHitResult tmpres;
        mgnear::linesHit((int)edges.size(), &edges.front(), true, pt, tol,
                         tmpres.nearpt, tmpres.segment, &res.inside);
    }
    
    return res.dist;
}

bool MgPathShape::_hitTestBox(const Box2d& rect) const
{
    if (!__super::_hitTestBox(rect))
        return false;
    
    int n = _path.getCount();
    const Point2d* pts = _path.getPoints();
    const char* types = _path.getTypes();
    Point2d pos, ends, bz[7];
    int ret = 0;
    
    for (int i = 0; i < n && !ret; i++) {
        pos = ends;
        
        switch (types[i] & ~kGiCloseFigure) {
            case kGiMoveTo:
                ends = pts[i];
                break;
                
            case kGiLineTo:
                ends = pts[i];
                ret = rect.isIntersect(Box2d(pos, ends));
                break;
{'fraction_non_alphanumeric': 0.13574899640819776, 'fraction_numerical': 0.010775406718783014, 'mean_word_length': 1.5655826558265582, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6408624', 'n_tokens_mistral': 3362, 'n_tokens_neox': 3169, 'n_words': 659}