找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2279|回复: 4

[每日一码] 射线法判断点是否在曲线内(C#版)

[复制链接]

已领礼包: 13个

财富等级: 恭喜发财

发表于 2017-8-12 00:27:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
[C#] 纯文本查看 复制代码
enum IncidenceType
{
    kIncidenceToLeft = 0,
    kIncidenceToRight,
    kIncidenceToFront,
    kIncidenceUnknown
};
 
IncidenceType CurveIncidence(Curve curve, double param, Vector3d dir, Vector3d normal)
{
    Vector3d deriv1 = curve.GetFirstDerivative(param);
 
    if(deriv1.IsParallelTo(dir))
    {
        // need second degree analysis
        Vector3d deriv2 = curve.GetSecondDerivative(param);
 
        if( deriv2.IsZeroLength() || deriv2.IsParallelTo(dir))
        {
            return IncidenceType.kIncidenceToFront;
        }
        else
        {
            if(deriv2.CrossProduct(dir).DotProduct(normal) < 0)
            {
                return IncidenceType.kIncidenceToRight;
            }
            else
            {
                return IncidenceType.kIncidenceToLeft;
            }
        }
    }
    if(deriv1.CrossProduct(dir).DotProduct(normal) < 0)
    {
        return IncidenceType.kIncidenceToLeft;
    }
    else
    {
        return IncidenceType.kIncidenceToRight;
    }
}
 
bool IsInsideCurve(Curve curve, Point3d testPt)
{
    if(!curve.Closed)
    {
        // cannot be inside
        return false;
    }
 
    Point3d ptOnCurve = curve.GetClosestPointTo(testPt, false);
 
    if( testPt == ptOnCurve)
    {
        return true;
    }
 
    if(!curve.IsPlanar)
    {
        return false;
    }
 
    // check its planar
    Plane plane = curve.GetPlane();
 
    // make the test ray from the plane
    double epsilon = 2e-6; // ( trust me on this )
 
    Point3dCollection IntersectionPoints = new Point3dCollection();
    Vector3d normal = plane.Normal;
    Vector3d testVector = normal.GetPerpendicularVector();
 
    using (Ray ray = new Ray())
    {
        ray.BasePoint = testPt;
 
        int nGlancingHits = 0, numberOfInters = 0;
        bool bRetryWithOtherRayDirection;
 
        do
        {
            bRetryWithOtherRayDirection = false;
 
            IntersectionPoints.Clear();
 
            ray.UnitDir = testVector;
 
            // fire the ray at the curve
            curve.IntersectWith(ray,
                Intersect.OnBothOperands,
                IntersectionPoints,
                IntPtr.Zero,
                IntPtr.Zero);
 
            numberOfInters = IntersectionPoints.Count;
 
            if (numberOfInters == 0)
            {
                return false;
            }
 
            nGlancingHits = 0;
 
            for (int i = 0; i < IntersectionPoints.Count; ++i)
            {
                double hitParam;
 
                try
                {
                    //This try/catch block circumvents an issue with GetParameterAtPoint API
                    hitParam = curve.GetParameterAtPoint(IntersectionPoints[i]);
                }
                catch
                {
                    bRetryWithOtherRayDirection = true;
                    testVector = testVector.RotateBy(5.0 * Math.PI / 180.0, normal);
                    break;
                }
 
                double inParam = hitParam - epsilon;
                double outParam = hitParam + epsilon;
 
                //Loop back inside the curve if param is falling outside of range
                if (inParam < curve.StartParam)
                    inParam = curve.EndParam - epsilon + (curve.StartParam - inParam);
 
                if (outParam > curve.EndParam)
                    outParam = curve.StartParam + epsilon + (curve.EndParam - outParam);
 
                IncidenceType inIncidence = CurveIncidence(curve, inParam, testVector, normal);
                IncidenceType outIncidence = CurveIncidence(curve, outParam, testVector, normal);
 
                if (inIncidence == IncidenceType.kIncidenceToFront || outIncidence == IncidenceType.kIncidenceToFront)
                {
                    bRetryWithOtherRayDirection = true;
                    testVector = testVector.RotateBy(5.0 * Math.PI / 180.0, normal);
                    break;
                }
 
                if ((inIncidence == IncidenceType.kIncidenceToRight && outIncidence == IncidenceType.kIncidenceToLeft) ||
                    (inIncidence == IncidenceType.kIncidenceToLeft && outIncidence == IncidenceType.kIncidenceToRight))
                {
                    nGlancingHits++;
                }
            }
        }
        while (bRetryWithOtherRayDirection);
 
        return ((numberOfInters + nGlancingHits) % 2 == 1);
    }
}
 


[C#] 纯文本查看 复制代码
[CommandMethod("TestIsInsideCurve")]
public void TestIsInsideCurve()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;
 
    PromptEntityOptions peo = new PromptEntityOptions("\nSelect a Curve: ");
    peo.SetRejectMessage("\nInvalid selection...");
    peo.AddAllowedClass(typeof(Curve), false);
 
    PromptEntityResult per = ed.GetEntity(peo);
 
    if (per.Status != PromptStatus.OK)
        return;
 
    PromptPointResult ppr = ed.GetPoint("\nPick a point");
 
    if (ppr.Status != PromptStatus.OK)
        return;
 
    using (Transaction Tx = db.TransactionManager.StartTransaction())
    {
        Curve curve = Tx.GetObject(per.ObjectId, OpenMode.ForRead) as Curve;
 
        bool res = IsInsideCurve(curve, ppr.Value);
 
        ed.WriteMessage("\nInside: " + res.ToString());
    }
}


评分

参与人数 1D豆 +5 收起 理由
gdfyhao + 5 很给力!经验;技术要点;资料分享奖!

查看全部评分

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 1个

财富等级: 恭喜发财

发表于 2018-5-11 11:38:31 | 显示全部楼层
很酷呀。。。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复

使用道具 举报

发表于 2020-5-30 10:17:37 | 显示全部楼层
好好!!!!学习了谢谢!!!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 82个

财富等级: 招财进宝

发表于 2020-6-6 16:00:23 | 显示全部楼层
可以可以
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复

使用道具 举报

已领礼包: 7个

财富等级: 恭喜发财

发表于 2020-10-27 18:22:51 | 显示全部楼层
看起来像是用射线法计算的,学习一下
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-12-22 20:02 , Processed in 0.345178 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表