TheSwamp

Code Red => .NET => Topic started by: wannabe on June 26, 2009, 07:04:39 AM

Title: Ascertaining Relative Location To Curve
Post by: wannabe on June 26, 2009, 07:04:39 AM
Does anyone have any suggestions about how I can ascertain which side of a curve an object is on.

I originally though that querying the X and Y of the object's centre and the point perpendicular on the curve would work. However, if there are extreme meanders, a line going south East for example could be on the left or the right depending how far a long the curve its perpendicular point is.

My current thought is to align the ucs with the perpendicular point and a point a small distance along the line. I'm not sure even this would be fullt accurate or if there is an ideal I haven't come across yet.

Any suggestions?

Nick
Title: Re: Ascertaining Relative Location To Curve
Post by: sinc on June 26, 2009, 08:10:36 AM
This is what I do.  I believe this code is in the CurveUtil class in the source code I have posted on my website (http://"http://www.quuxsoft.com/SincpacC3D_source.aspx").

Code: [Select]
        /// <summary>
        /// Returns +1 if p3 is on right side of line formed by p1-p2, or
        /// returns -1 if p3 is on lefts side of line formed by p1-p2.  Points
        /// are flattend to XY plane.
        /// </summary>
        public static int DeflectionDirection(Point3d p1, Point3d p2, Point3d p3)
        {
            return DeflectionDirection(
                new Point2d(p1.X, p1.Y),
                new Point2d(p2.X, p2.Y),
                new Point2d(p3.X, p3.Y)
                );
        }

        /// <summary>
        /// Returns +1 if p3 is on right side of line formed by p1-p2, or
        /// returns -1 if p3 is on lefts side of line formed by p1-p2.
        /// </summary>
        public static int DeflectionDirection(Point2d p1, Point2d p2, Point2d p3)
        {
            double crossProduct = ((p2.X - p1.X) * (p3.Y - p1.Y)) - ((p2.Y - p1.Y) * (p3.X - p1.X));
            return (crossProduct > 0) ? -1 : 1;
        }

        public static int DeflectionDirection(Curve curve, Point3d point)
        {
            Point3d pointOnCurve = curve.GetClosestPointTo(point, Vector3d.ZAxis, false);
            return DeflectionDirection(curve, point, pointOnCurve);
        }

        public static int DeflectionDirection(Curve curve, Point3d point, Point3d pointOnCurve)
        {
            double dist = curve.GetDistAtPoint(pointOnCurve);
            Point3d pol2;
            if ((dist + .01) > curve.GetDistanceAtParameter(curve.EndParam))
            {
                pol2 = pointOnCurve;
                pointOnCurve = curve.GetPointAtDist(dist - .01);
            }
            else
            {
                pol2 = curve.GetPointAtDist(dist + .01);
            }
            return CurveUtil.DeflectionDirection(pointOnCurve, pol2, point);
        }
Title: Re: Ascertaining Relative Location To Curve
Post by: wannabe on June 26, 2009, 09:35:42 AM
I can't acces the link from sinc on the work's machine so I'll try it at home. In the meantime, I'm having a slight difficulty getting an offset version of my curve. Here's the code which crashes in the first line of my transaction whilst trying to cast the object to a curve (the object returned as a DBObjectcollection returned from the Curve.GetOffsetCurves() method.

Here's the offending code:

Code: [Select]
private static string getOffsetSide(BlockReference block)
        {
            double distToL;
            double distToR;

            //1. Offset curve a small amount in both directions
            DBObjectCollection curveLCollection = SelectedCurve.GetOffsetCurves(1.0);
            DBObjectCollection curveRCollection = SelectedCurve.GetOffsetCurves(-1.0);

            //2. Add to current space
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                Curve curveL = (Curve)trans.GetObject(curveLCollection[0].ObjectId, OpenMode.ForWrite);
                Curve curveR = (Curve)trans.GetObject(curveRCollection[0].ObjectId, OpenMode.ForWrite);

                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                currentSpace.AppendEntity(curveL);
                currentSpace.AppendEntity(curveR);


                //3. Measure distance to both curves
                Point3d blockCentre = new Point3d(block.Position.X, block.Position.Y, 0);

                Point3d curveLPoint = curveL.GetClosestPointTo(blockCentre, false);
                Line lineToL = new Line(blockCentre, new Point3d(curveLPoint.X, curveLPoint.Y, 0));
                distToL = lineToL.Length;

                Point3d curveRPoint = curveR.GetClosestPointTo(blockCentre, false);
                Line lineToR = new Line(blockCentre, new Point3d(curveRPoint.X, curveRPoint.Y, 0));
                distToR = lineToR.Length;

                //4 dispose of curves
                curveL.Erase();
                curveR.Erase();

                trans.Abort();
            }
Title: Re: Ascertaining Relative Location To Curve
Post by: Bryco on June 26, 2009, 10:02:15 AM
The way you posed the question
Quote
which side of a curve an object is on.
you need to start with bounding boxes as unless you know the size of the object you don't know what point to use on the object. There is a possibility that the object is touching/ intersecting the curve.
Title: Re: Ascertaining Relative Location To Curve
Post by: wannabe on June 26, 2009, 10:08:45 AM
I've made some progress:

Code: [Select]
foreach (Object id in curveLCollection)
                {
                    Curve segment = (Curve)id;
                  
                }

EDIT: The above works  :lol: :lol: :lol:



Thanks.

The way you posed the question
Quote
which side of a curve an object is on.
you need to start with bounding boxes as unless you know the size of the object you don't know what point to use on the object. There is a possibility that the object is touching/ intersecting the curve.
Title: Re: Ascertaining Relative Location To Curve
Post by: Spike Wilbury on June 26, 2009, 10:27:30 AM
This is how I would do, to use the GetOffsetCurves method, on a quick code that offset a curve to both sides:

Code: [Select]
[CommandMethod("MYOFFSET")]
public void myoffset()
{
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptEntityResult res = ed.GetEntity("\nSelect curve to offset both sides: ");
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Curve curve = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
        if (curve != null)
        {
            double offsetDist = 2.0;
            DBObjectCollection curvesPositiveSide = curve.GetOffsetCurves(offsetDist);
            DBObjectCollection curvesNegativeSide = curve.GetOffsetCurves(-offsetDist);
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            foreach (DBObject obj in curvesPositiveSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
            foreach (DBObject obj in curvesNegativeSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
        }
        tr.Commit();
    }
}

might help... maybe.
Title: Re: Ascertaining Relative Location To Curve
Post by: wannabe on June 26, 2009, 10:33:06 AM
This is how I would do, to use the GetOffsetCurves method, on a quick code that offset a curve to both sides:

Code: [Select]
[CommandMethod("MYOFFSET")]
public void myoffset()
{
    Document doc = acadApp.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;
    PromptEntityResult res = ed.GetEntity("\nSelect curve to offset both sides: ");
    if (res.Status != PromptStatus.OK) return;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Curve curve = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
        if (curve != null)
        {
            double offsetDist = 2.0;
            DBObjectCollection curvesPositiveSide = curve.GetOffsetCurves(offsetDist);
            DBObjectCollection curvesNegativeSide = curve.GetOffsetCurves(-offsetDist);
            BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            foreach (DBObject obj in curvesPositiveSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
            foreach (DBObject obj in curvesNegativeSide)
            {
                btr.AppendEntity((Entity)obj);
                tr.AddNewlyCreatedDBObject(obj, true);
            }
        }
        tr.Commit();
    }
}

might help... maybe.

Yeah, thats an interesting way to do things and I definitely appreciate the contribution.

I don't really want to keep the curves at the moment. They are just used to work out two distances and then they are not needed.

Cheers again.
Title: Re: Ascertaining Relative Location To Curve
Post by: Spike Wilbury on June 26, 2009, 11:16:32 AM
Quote
I don't really want to keep the curves at the moment. They are just used to work out two distances and then they are not needed.

I was providing a way to implement the GetOffsetCurves method.

If you want to work on the offset curves, you do not need to call the AppendEntity();

Here is a way to do it:

Code: [Select]
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
PromptEntityResult res = ed.GetEntity("\nSelect curve to offset both sides: ");
if (res.Status != PromptStatus.OK) return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
    Curve curve = tr.GetObject(res.ObjectId, OpenMode.ForRead, false) as Curve;
    if (curve != null)
    {
        double offsetDist = 2.0;
        DBObjectCollection curvesPositiveSide = curve.GetOffsetCurves(offsetDist);
        DBObjectCollection curvesNegativeSide = curve.GetOffsetCurves(-offsetDist);
        Curve curvePos = (Curve)curvesPositiveSide[0];
        Curve curveNeg = (Curve)curvesNegativeSide[0];

        Point3d sp = new Point3d();
        Point3d ep = new Point3d();
        double d = 0.0;
        if (curvePos != null)
            sp = curvePos.StartPoint;
        if (curveNeg != null)
            ep = curveNeg.StartPoint;

        d = sp.DistanceTo(ep); // distance from both points
    }
    tr.Commit();
}

might help... maybe
Title: Re: Ascertaining Relative Location To Curve
Post by: It's Alive! on June 26, 2009, 11:26:40 AM
Hi Luis,

in this case, would you need to iterate through the DBObjectCollections'
disposing of each object that was not added the to DB?

Title: Re: Ascertaining Relative Location To Curve
Post by: Spike Wilbury on June 26, 2009, 11:29:49 AM
Hi Luis,

in this case, would you need to iterate through the DBObjectCollections'
disposing of each object that was not added the to DB?



Hi Daniel,

I say yes... but
Hmm don't they go away on the tr.Commit(); ... I was trying to demostrate on a quicky code - how to use those objects without added to the database... :)
Let me check...
Title: Re: Ascertaining Relative Location To Curve
Post by: It's Alive! on June 26, 2009, 11:35:21 AM
Hmm don't they go away on the tr.Commit();

Ah yes, are those objects transatcion residient?... good point  :laugh:
Title: Re: Ascertaining Relative Location To Curve
Post by: sinc on June 26, 2009, 11:49:42 AM
If you create a DBObject and do not add it to a Transaction, you must dispose of it yourself.  Autocad will get wobbly and probably crash otherwise.
Title: Re: Ascertaining Relative Location To Curve
Post by: Spike Wilbury on June 26, 2009, 12:16:06 PM
have been out of the C# coding... but I think they are disposed inside of the using { ... }... but I'm not a C# expert  :-(


I have tried several times to crash autocad with that code, and no luck....
Title: Re: Ascertaining Relative Location To Curve
Post by: It's Alive! on June 26, 2009, 12:29:01 PM
It's not a big deal since those objects have finalizers that should do the cleanup,
I think there was an issue when the collection was disposed before the object(s) it contained were disposed. 
Title: Re: Ascertaining Relative Location To Curve
Post by: wannabe on June 29, 2009, 03:32:00 AM
Back on the subject of 'my curves' , I'm having a small issue with the following code snippet. In one of my drawings, it was giving me a null reference exception. Having stepped throught the code I've found it to be the curveRCollection: there was no object being stored in it, yet the curveLCollection was holding the offset curve as intended.

I've tested the code on a few other drawings and it works fine on those (the curveRCollection is being populated as expected).

Any ideas?

Code: [Select]
   //1. Offset curve a small amount in both directions

            DBObjectCollection curveLCollection = SelectedCurve.GetOffsetCurves(0.001);
            DBObjectCollection curveRCollection = SelectedCurve.GetOffsetCurves(-0.001);
           

            //2. Add to current space
            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
               
                foreach(object id in curveLCollection)
                curveL = (Curve)id;

                foreach (object id in curveRCollection)
                 curveR = (Curve)id;

                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                currentSpace.AppendEntity(curveL);
                currentSpace.AppendEntity(curveR);


                //3. Measure distance to both curves
                Point3d blockCentre = new Point3d(block.Position.X, block.Position.Y, 0);

                Point3d curveLPoint = curveL.GetClosestPointTo(blockCentre, false);
                Line lineToL = new Line(blockCentre, new Point3d(curveLPoint.X, curveLPoint.Y, 0));
                distToL = lineToL.Length;

                Point3d curveRPoint = curveR.GetClosestPointTo(blockCentre, false);
                Line lineToR = new Line(blockCentre, new Point3d(curveRPoint.X, curveRPoint.Y, 0));
                distToR = lineToR.Length;

                //4 dispose of curves
                curveL.Erase();
                curveR.Erase();

                trans.Abort();
Title: Re: Ascertaining Relative Location To Curve
Post by: Spike Wilbury on June 29, 2009, 10:24:20 AM
you need to check if the objects are valid first, before doing anything, and I never had use the call to trans.Abort();
Title: Re: Ascertaining Relative Location To Curve
Post by: wannabe on June 29, 2009, 10:41:58 AM
you need to check if the objects are valid first, before doing anything, and I never had use the call to trans.Abort();

The curve is being offset, hence the curveLCollection being populate with the single curve offset on the one side. However, the offset to the other is failing.
Title: Re: Ascertaining Relative Location To Curve
Post by: It's Alive! on June 29, 2009, 06:22:27 PM
Have alook at AcDbCurve::getOffsetCurves in the ARX docs. Aslo have you tried what sinc posted?